diff options
author | Clyne Sullivan <clyne@bitgloo.com> | 2021-01-22 21:43:36 -0500 |
---|---|---|
committer | Clyne Sullivan <clyne@bitgloo.com> | 2021-01-22 21:43:36 -0500 |
commit | 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 (patch) | |
tree | c14713aedfe78ee8b34f2e1252408782e2e2ff5d /ChibiOS_20.3.2/os/hal/ports | |
parent | e080a26651f90c88176140d63a74c93c2f4041a2 (diff) |
upload initial port
Diffstat (limited to 'ChibiOS_20.3.2/os/hal/ports')
229 files changed, 78200 insertions, 0 deletions
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk new file mode 100644 index 0000000..a3b7649 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c new file mode 100644 index 0000000..a8733f9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.c @@ -0,0 +1,485 @@ +/*
+ 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)
+
+/* Headers differences patches.*/
+#if defined(ADC_IER_AWDIE) && !defined(ADC_IER_AWD1IE)
+#define ADC_IER_AWD1IE ADC_IER_AWDIE
+#endif
+
+#if defined(ADC_ISR_AWD) && !defined(ADC_ISR_AWD1)
+#define ADC_ISR_AWD1 ADC_ISR_AWD
+#endif
+
+#define TR1 TR
+
+/*===========================================================================*/
+/* 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.*/
+#if STM32_ADC_SUPPORTS_PRESCALER
+ ADC->CCR = STM32_ADC_PRESC << 18;
+#else
+ ADC->CCR = 0;
+#endif
+
+ /* 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);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC1);
+#endif
+
+ /* 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.*/
+#if STM32_ADC_SUPPORTS_PRESCALER
+ ADC->CCR = STM32_ADC_PRESC << 18;
+#else
+ ADC->CCR = 0;
+#endif
+
+ /* 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;
+ const ADCConversionGroup *grpp = adcp->grpp;
+
+ /* DMA setup.*/
+ mode = adcp->dmamode;
+ cfgr1 = grpp->cfgr1 | ADC_CFGR1_DMAEN;
+ 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;
+ adcp->adc->TR1 = grpp->tr;
+ adcp->adc->SMPR = grpp->smpr;
+ adcp->adc->CHSELR = grpp->chselr;
+
+ /* ADC configuration and start.*/
+ adcp->adc->CFGR1 = cfgr1;
+#if STM32_ADC_SUPPORTS_OVERSAMPLING == TRUE
+ {
+ uint32_t cfgr2 = adcp->adc->CFGR2 & STM32_ADC_CKMODE_MASK;
+ adcp->adc->CFGR2 = cfgr2 | grpp->cfgr2;
+ }
+#endif
+
+ /* 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->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 error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD);
+ }
+ }
+}
+
+/**
+ * @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 */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h new file mode 100644 index 0000000..cc478d5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/hal_adc_lld.h @@ -0,0 +1,415 @@ +/*
+ 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
+ * @{
+ */
+#if defined(STM32F0XX) || defined(__DOXYGEN__)
+#define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */
+#define ADC_SMPR_SMP_7P5 1U /**< @brief 21 cycles conversion time. */
+#define ADC_SMPR_SMP_13P5 2U /**< @brief 28 cycles conversion time. */
+#define ADC_SMPR_SMP_28P5 3U /**< @brief 41 cycles conversion time. */
+#define ADC_SMPR_SMP_41P5 4U /**< @brief 54 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_239P5 7U /**< @brief 252 cycles conversion time. */
+#elif defined(STM32L0XX)
+#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. */
+#endif
+/** @} */
+
+/**
+ * @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)
+
+#if (STM32_ADC_SUPPORTS_OVERSAMPLING == TRUE) || defined(__DOXYGEN__)
+#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)
+#endif
+/** @} */
+
+/**
+ * @name Threashold register 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
+
+#if (STM32_ADC_SUPPORTS_PRESCALER == TRUE) || defined(__DOXYGEN__)
+/*
+ * @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
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Supported devices checks.*/
+#if !defined(STM32F0XX) && !defined(STM32L0XX)
+#error "ADCv1 only supports F0 and L0 STM32 devices"
+#endif
+
+#if defined(STM32L0XX) || defined(__DOXYGEN__)
+#define STM32_ADCV1_OVERSAMPLING TRUE
+#else
+#define STM32_ADCV1_OVERSAMPLING FALSE
+#endif
+
+/* Registry checks.*/
+#if !defined(STM32_HAS_ADC1)
+#error "STM32_HAS_ADC1 not defined in registry"
+#endif
+
+#if !defined(STM32_ADC_SUPPORTS_PRESCALER)
+#error "STM32_ADC_SUPPORTS_PRESCALER 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
+#if STM32_DMA_SUPPORTS_DMAMUX
+
+#else /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_ADC_USE_ADC1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK)
+#error "invalid DMA stream associated to ADC1"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* ADC clock source checks.*/
+#if STM32_ADC_SUPPORTS_PRESCALER == TRUE
+#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
+#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;
+
+/*===========================================================================*/
+/* 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.
+ */
+#if (STM32_ADC_SUPPORTS_OVERSAMPLING == TRUE) || defined(__DOXYGEN__)
+#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 TR register initialization data.*/ \
+ uint32_t tr; \
+ /* 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
+#else
+#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 TR register initialization data.*/ \
+ uint32_t tr; \
+ /* 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
+#endif
+
+/**
+ * @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 */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt new file mode 100644 index 0000000..9224117 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv1/notes.txt @@ -0,0 +1,16 @@ +STM32 ADCv1 driver.
+
+Driver capability:
+
+- Supports the STM32 "simple" ADC, the one found on small devices (F0, L0).
+
+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.
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk new file mode 100644 index 0000000..9be6513 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c new file mode 100644 index 0000000..53a5439 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c @@ -0,0 +1,452 @@ +/*
+ 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 ADCv2/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)
+
+#define ADC2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_CHN)
+
+#define ADC3_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief ADC1 driver identifier.*/
+#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__)
+ADCDriver ADCD1;
+#endif
+
+/** @brief ADC2 driver identifier.*/
+#if STM32_ADC_USE_ADC2 || defined(__DOXYGEN__)
+ADCDriver ADCD2;
+#endif
+
+/** @brief ADC3 driver identifier.*/
+#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__)
+ADCDriver ADCD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @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 || STM32_ADC_USE_ADC2 || STM32_ADC_USE_ADC3 || \
+ defined(__DOXYGEN__)
+/**
+ * @brief ADC interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC_HANDLER) {
+ uint32_t sr;
+
+ OSAL_IRQ_PROLOGUE();
+
+#if STM32_ADC_USE_ADC1
+ sr = ADC1->SR;
+ ADC1->SR = 0;
+ /* 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 ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD1.dmastp) > 0)) {
+ /* ADC overflow condition, this could happen only if the DMA is unable
+ to read data fast enough.*/
+ if (ADCD1.grpp != NULL)
+ _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW);
+ }
+ if (sr & ADC_SR_AWD) {
+ if (ADCD1.grpp != NULL) {
+ _adc_isr_error_code(&ADCD1, ADC_ERR_WATCHDOG);
+ }
+ }
+#if defined(STM32_ADC_ADC1_IRQ_HOOK)
+ STM32_ADC_ADC1_IRQ_HOOK
+#endif
+#endif /* STM32_ADC_USE_ADC1 */
+
+#if STM32_ADC_USE_ADC2
+ sr = ADC2->SR;
+ ADC2->SR = 0;
+ /* 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 ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD2.dmastp) > 0)) {
+ /* ADC overflow condition, this could happen only if the DMA is unable
+ to read data fast enough.*/
+ if (ADCD2.grpp != NULL)
+ _adc_isr_error_code(&ADCD2, ADC_ERR_OVERFLOW);
+ }
+ if (sr & ADC_SR_AWD) {
+ if (ADCD2.grpp != NULL) {
+ _adc_isr_error_code(&ADCD2, ADC_ERR_WATCHDOG);
+ }
+ }
+#if defined(STM32_ADC_ADC2_IRQ_HOOK)
+ STM32_ADC_ADC2_IRQ_HOOK
+#endif
+#endif /* STM32_ADC_USE_ADC2 */
+
+#if STM32_ADC_USE_ADC3
+ sr = ADC3->SR;
+ ADC3->SR = 0;
+ /* 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 ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD3.dmastp) > 0)) {
+ /* ADC overflow condition, this could happen only if the DMA is unable
+ to read data fast enough.*/
+ if (ADCD3.grpp != NULL)
+ _adc_isr_error_code(&ADCD3, ADC_ERR_OVERFLOW);
+ }
+ if (sr & ADC_SR_AWD) {
+ if (ADCD3.grpp != NULL) {
+ _adc_isr_error_code(&ADCD3, ADC_ERR_WATCHDOG);
+ }
+ }
+#if defined(STM32_ADC_ADC3_IRQ_HOOK)
+ STM32_ADC_ADC3_IRQ_HOOK
+#endif
+#endif /* STM32_ADC_USE_ADC3 */
+
+ 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;
+#endif
+
+#if STM32_ADC_USE_ADC2
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD2);
+ ADCD2.adc = ADC2;
+ ADCD2.dmastp = NULL;
+ ADCD2.dmamode = STM32_DMA_CR_CHSEL(ADC2_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_ADC_ADC2_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
+
+#if STM32_ADC_USE_ADC3
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD3);
+ ADCD3.adc = ADC3;
+ ADCD3.dmastp = NULL;
+ ADCD3.dmamode = STM32_DMA_CR_CHSEL(ADC3_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_ADC_ADC3_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 because sharing.*/
+ nvicEnableVector(STM32_ADC_NUMBER, STM32_ADC_IRQ_PRIORITY);
+}
+
+/**
+ * @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");
+ dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR);
+ rccEnableADC1(true);
+ }
+#endif /* STM32_ADC_USE_ADC1 */
+
+#if STM32_ADC_USE_ADC2
+ if (&ADCD2 == adcp) {
+ adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC2_DMA_STREAM,
+ STM32_ADC_ADC2_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_rx_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
+ dmaStreamSetPeripheral(adcp->dmastp, &ADC2->DR);
+ rccEnableADC2(true);
+ }
+#endif /* STM32_ADC_USE_ADC2 */
+
+#if STM32_ADC_USE_ADC3
+ if (&ADCD3 == adcp) {
+ adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC3_DMA_STREAM,
+ STM32_ADC_ADC3_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_rx_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
+ dmaStreamSetPeripheral(adcp->dmastp, &ADC3->DR);
+ rccEnableADC3(true);
+ }
+#endif /* STM32_ADC_USE_ADC3 */
+
+ /* This is a common register but apparently it requires that at least one
+ of the ADCs is clocked in order to allow writing, see bug 3575297.*/
+ ADC->CCR = (ADC->CCR & (ADC_CCR_TSVREFE | ADC_CCR_VBATE)) |
+ (STM32_ADC_ADCPRE << 16);
+
+ /* ADC initial setup, starting the analog part here in order to reduce
+ the latency when starting a conversion.*/
+ adcp->adc->CR1 = 0;
+ adcp->adc->CR2 = 0;
+ adcp->adc->CR2 = ADC_CR2_ADON;
+ }
+}
+
+/**
+ * @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.*/
+ if (adcp->state == ADC_READY) {
+
+ dmaStreamFreeI(adcp->dmastp);
+ adcp->dmastp = NULL;
+
+ adcp->adc->CR1 = 0;
+ adcp->adc->CR2 = 0;
+
+#if STM32_ADC_USE_ADC1
+ if (&ADCD1 == adcp)
+ rccDisableADC1();
+#endif
+
+#if STM32_ADC_USE_ADC2
+ if (&ADCD2 == adcp)
+ rccDisableADC2();
+#endif
+
+#if STM32_ADC_USE_ADC3
+ if (&ADCD3 == adcp)
+ rccDisableADC3();
+#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;
+ uint32_t cr2;
+ const ADCConversionGroup *grpp = adcp->grpp;
+
+ /* DMA setup.*/
+ mode = adcp->dmamode;
+ if (grpp->circular) {
+ mode |= STM32_DMA_CR_CIRC;
+ 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.*/
+ adcp->adc->SR = 0;
+ adcp->adc->SMPR1 = grpp->smpr1;
+ adcp->adc->SMPR2 = grpp->smpr2;
+ adcp->adc->HTR = grpp->htr;
+ adcp->adc->LTR = grpp->ltr;
+ adcp->adc->SQR1 = grpp->sqr1 | ADC_SQR1_NUM_CH(grpp->num_channels);
+ adcp->adc->SQR2 = grpp->sqr2;
+ adcp->adc->SQR3 = grpp->sqr3;
+
+ /* ADC configuration and start.*/
+ adcp->adc->CR1 = grpp->cr1 | ADC_CR1_OVRIE | ADC_CR1_SCAN;
+
+ /* Enforcing the mandatory bits in CR2.*/
+ cr2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_ADON;
+
+ /* The start method is different dependign if HW or SW triggered, the
+ start is performed using the method specified in the CR2 configuration.*/
+ if ((cr2 & ADC_CR2_SWSTART) != 0) {
+ /* Initializing CR2 while keeping ADC_CR2_SWSTART at zero.*/
+ adcp->adc->CR2 = (cr2 | ADC_CR2_CONT) & ~ADC_CR2_SWSTART;
+
+ /* Finally enabling ADC_CR2_SWSTART.*/
+ adcp->adc->CR2 = (cr2 | ADC_CR2_CONT);
+ }
+ else
+ adcp->adc->CR2 = cr2;
+}
+
+/**
+ * @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);
+ adcp->adc->CR1 = 0;
+ /* Because ticket #822, preserving injected conversions.*/
+ adcp->adc->CR2 &= ~(ADC_CR2_SWSTART);
+ adcp->adc->CR2 = ADC_CR2_ADON;
+}
+
+/**
+ * @brief Enables the TSVREFE bit.
+ * @details The TSVREFE bit is required in order to sample the internal
+ * temperature sensor and internal reference voltage.
+ * @note This is an STM32-only functionality.
+ */
+void adcSTM32EnableTSVREFE(void) {
+
+ ADC->CCR |= ADC_CCR_TSVREFE;
+}
+
+/**
+ * @brief Disables the TSVREFE bit.
+ * @details The TSVREFE bit is required in order to sample the internal
+ * temperature sensor and internal reference voltage.
+ * @note This is an STM32-only functionality.
+ */
+void adcSTM32DisableTSVREFE(void) {
+
+ ADC->CCR &= ~ADC_CCR_TSVREFE;
+}
+
+/**
+ * @brief Enables the VBATE bit.
+ * @details The VBATE 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().
+ */
+void adcSTM32EnableVBATE(void) {
+
+ ADC->CCR |= ADC_CCR_VBATE;
+}
+
+/**
+ * @brief Disables the VBATE bit.
+ * @details The VBATE 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().
+ */
+void adcSTM32DisableVBATE(void) {
+
+ ADC->CCR &= ~ADC_CCR_VBATE;
+}
+
+#endif /* HAL_USE_ADC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h new file mode 100644 index 0000000..5202f94 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h @@ -0,0 +1,486 @@ +/*
+ 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 ADCv2/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 Absolute Maximum Ratings
+ * @{
+ */
+/**
+ * @brief Minimum ADC clock frequency.
+ */
+#define STM32_ADCCLK_MIN 600000
+
+/**
+ * @brief Maximum ADC clock frequency.
+ */
+#if defined(STM32F4XX) || defined(__DOXYGEN__)
+#define STM32_ADCCLK_MAX 36000000
+#else
+#define STM32_ADCCLK_MAX 30000000
+#endif
+/** @} */
+
+/**
+ * @name Triggers selection
+ * @{
+ */
+#define ADC_CR2_EXTEN_MASK (3U << 28U)
+#define ADC_CR2_EXTEN_DISABLED (0U << 28U)
+#define ADC_CR2_EXTEN_RISING (1U << 28U)
+#define ADC_CR2_EXTEN_FALLING (2U << 28U)
+#define ADC_CR2_EXTEN_BOTH (3U << 28U)
+
+#define ADC_CR2_EXTSEL_MASK (15U << 24U)
+#define ADC_CR2_EXTSEL_SRC(n) ((n) << 24U)
+/** @} */
+
+/**
+ * @name ADC clock divider settings
+ * @{
+ */
+#define ADC_CCR_ADCPRE_DIV2 0
+#define ADC_CCR_ADCPRE_DIV4 1
+#define ADC_CCR_ADCPRE_DIV6 2
+#define ADC_CCR_ADCPRE_DIV8 3
+/** @} */
+
+/**
+ * @name Available analog channels
+ * @{
+ */
+#define ADC_CHANNEL_IN0 0 /**< @brief External analog input 0. */
+#define ADC_CHANNEL_IN1 1 /**< @brief External analog input 1. */
+#define ADC_CHANNEL_IN2 2 /**< @brief External analog input 2. */
+#define ADC_CHANNEL_IN3 3 /**< @brief External analog input 3. */
+#define ADC_CHANNEL_IN4 4 /**< @brief External analog input 4. */
+#define ADC_CHANNEL_IN5 5 /**< @brief External analog input 5. */
+#define ADC_CHANNEL_IN6 6 /**< @brief External analog input 6. */
+#define ADC_CHANNEL_IN7 7 /**< @brief External analog input 7. */
+#define ADC_CHANNEL_IN8 8 /**< @brief External analog input 8. */
+#define ADC_CHANNEL_IN9 9 /**< @brief External analog input 9. */
+#define ADC_CHANNEL_IN10 10 /**< @brief External analog input 10. */
+#define ADC_CHANNEL_IN11 11 /**< @brief External analog input 11. */
+#define ADC_CHANNEL_IN12 12 /**< @brief External analog input 12. */
+#define ADC_CHANNEL_IN13 13 /**< @brief External analog input 13. */
+#define ADC_CHANNEL_IN14 14 /**< @brief External analog input 14. */
+#define ADC_CHANNEL_IN15 15 /**< @brief External analog input 15. */
+#define ADC_CHANNEL_SENSOR 16 /**< @brief Internal temperature sensor.
+ @note Available onADC1 only. */
+#define ADC_CHANNEL_VREFINT 17 /**< @brief Internal reference.
+ @note Available onADC1 only. */
+#define ADC_CHANNEL_VBAT 18 /**< @brief VBAT.
+ @note Available onADC1 only. */
+/** @} */
+
+/**
+ * @name Sampling rates
+ * @{
+ */
+#define ADC_SAMPLE_3 0 /**< @brief 3 cycles sampling time. */
+#define ADC_SAMPLE_15 1 /**< @brief 15 cycles sampling time. */
+#define ADC_SAMPLE_28 2 /**< @brief 28 cycles sampling time. */
+#define ADC_SAMPLE_56 3 /**< @brief 56 cycles sampling time. */
+#define ADC_SAMPLE_84 4 /**< @brief 84 cycles sampling time. */
+#define ADC_SAMPLE_112 5 /**< @brief 112 cycles sampling time. */
+#define ADC_SAMPLE_144 6 /**< @brief 144 cycles sampling time. */
+#define ADC_SAMPLE_480 7 /**< @brief 480 cycles sampling time. */
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief ADC common clock divider.
+ * @note This setting is influenced by the VDDA voltage and other
+ * external conditions, please refer to the datasheet for more
+ * info.<br>
+ * See section 5.3.20 "12-bit ADC characteristics".
+ */
+#if !defined(STM32_ADC_ADCPRE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV2
+#endif
+
+/**
+ * @brief ADC1 driver enable switch.
+ * @details If set to @p TRUE the support for ADC1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__)
+#define STM32_ADC_USE_ADC1 FALSE
+#endif
+
+/**
+ * @brief ADC2 driver enable switch.
+ * @details If set to @p TRUE the support for ADC2 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ADC_USE_ADC2) || defined(__DOXYGEN__)
+#define STM32_ADC_USE_ADC2 FALSE
+#endif
+
+/**
+ * @brief ADC3 driver enable switch.
+ * @details If set to @p TRUE the support for ADC3 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ADC_USE_ADC3) || defined(__DOXYGEN__)
+#define STM32_ADC_USE_ADC3 FALSE
+#endif
+
+/**
+ * @brief DMA stream used for ADC1 operations.
+ */
+#if !defined(STM32_ADC_ADC1_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
+#endif
+
+/**
+ * @brief DMA stream used for ADC2 operations.
+ */
+#if !defined(STM32_ADC_ADC2_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
+#endif
+
+/**
+ * @brief DMA stream used for ADC3 operations.
+ */
+#if !defined(STM32_ADC_ADC3_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
+#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 ADC2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_ADC_ADC2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief ADC3 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief ADC interrupt priority level setting.
+ * @note This setting is shared among ADC1, ADC2 and ADC3 because
+ * all ADCs share the same vector.
+ */
+#if !defined(STM32_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_IRQ_PRIORITY 5
+#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 5
+#endif
+
+/**
+ * @brief ADC2 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 5
+#endif
+
+/**
+ * @brief ADC3 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 5
+#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_ADC2 && !STM32_HAS_ADC2
+#error "ADC2 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_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3
+#error "ADC driver activated but no ADC peripheral assigned"
+#endif
+
+#if STM32_ADC_USE_ADC1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK)
+#error "invalid DMA stream associated to ADC1"
+#endif
+
+#if STM32_ADC_USE_ADC2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_MSK)
+#error "invalid DMA stream associated to ADC2"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_MSK)
+#error "invalid DMA stream associated to ADC3"
+#endif
+
+/* ADC clock related settings and checks.*/
+#if STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV2
+#define STM32_ADCCLK (STM32_PCLK2 / 2)
+#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV4
+#define STM32_ADCCLK (STM32_PCLK2 / 4)
+#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV6
+#define STM32_ADCCLK (STM32_PCLK2 / 6)
+#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV8
+#define STM32_ADCCLK (STM32_PCLK2 / 8)
+#else
+#error "invalid STM32_ADC_ADCPRE value specified"
+#endif
+
+#if (STM32_ADCCLK < STM32_ADCCLK_MIN) || (STM32_ADCCLK > STM32_ADCCLK_MAX)
+#error "STM32_ADCCLK outside acceptable range (STM32_ADCCLK_MIN...STM32_ADCCLK_MAX)"
+#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_WATCHDOG = 2 /**< ADC watchdog condition. */
+} 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 CR1 register initialization data. \
+ NOTE: All the required bits must be defined into this field except \
+ @p ADC_CR1_SCAN that is enforced inside the driver.*/ \
+ uint32_t cr1; \
+ /* ADC CR2 register initialization data. \
+ NOTE: All the required bits must be defined into this field except \
+ @p ADC_CR2_DMA, @p ADC_CR2_CONT and @p ADC_CR2_ADON that are \
+ enforced inside the driver.*/ \
+ uint32_t cr2; \
+ /* ADC SMPR1 register initialization data. \
+ NOTE: In this field must be specified the sample times for channels \
+ 10...18.*/ \
+ uint32_t smpr1; \
+ /* ADC SMPR2 register initialization data. \
+ NOTE: In this field must be specified the sample times for channels \
+ 0...9.*/ \
+ uint32_t smpr2; \
+ /* ADC watchdog high threshold register. \
+ NOTE: This field defines the high threshold of the analog watchdog.*/ \
+ uint16_t htr; \
+ /* ADC watchdog low threshold register. \
+ NOTE: This field defines the low threshold of the analog watchdog.*/ \
+ uint16_t ltr; \
+ /* ADC SQR1 register initialization data. \
+ NOTE: Conversion group sequence 13...16 + sequence length.*/ \
+ uint32_t sqr1; \
+ /* ADC SQR2 register initialization data. \
+ NOTE: Conversion group sequence 7...12.*/ \
+ uint32_t sqr2; \
+ /* ADC SQR3 register initialization data. \
+ NOTE: Conversion group sequence 1...6.*/ \
+ uint32_t sqr3
+
+/**
+ * @name Sequences building helper macros
+ * @{
+ */
+/**
+ * @brief Number of channels in a conversion sequence.
+ */
+#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
+
+#define ADC_SQR3_SQ1_N(n) ((n) << 0) /**< @brief 1st channel in seq. */
+#define ADC_SQR3_SQ2_N(n) ((n) << 5) /**< @brief 2nd channel in seq. */
+#define ADC_SQR3_SQ3_N(n) ((n) << 10) /**< @brief 3rd channel in seq. */
+#define ADC_SQR3_SQ4_N(n) ((n) << 15) /**< @brief 4th channel in seq. */
+#define ADC_SQR3_SQ5_N(n) ((n) << 20) /**< @brief 5th channel in seq. */
+#define ADC_SQR3_SQ6_N(n) ((n) << 25) /**< @brief 6th channel in seq. */
+
+#define ADC_SQR2_SQ7_N(n) ((n) << 0) /**< @brief 7th channel in seq. */
+#define ADC_SQR2_SQ8_N(n) ((n) << 5) /**< @brief 8th channel in seq. */
+#define ADC_SQR2_SQ9_N(n) ((n) << 10) /**< @brief 9th channel in seq. */
+#define ADC_SQR2_SQ10_N(n) ((n) << 15) /**< @brief 10th channel in seq.*/
+#define ADC_SQR2_SQ11_N(n) ((n) << 20) /**< @brief 11th channel in seq.*/
+#define ADC_SQR2_SQ12_N(n) ((n) << 25) /**< @brief 12th channel in seq.*/
+
+#define ADC_SQR1_SQ13_N(n) ((n) << 0) /**< @brief 13th channel in seq.*/
+#define ADC_SQR1_SQ14_N(n) ((n) << 5) /**< @brief 14th channel in seq.*/
+#define ADC_SQR1_SQ15_N(n) ((n) << 10) /**< @brief 15th channel in seq.*/
+#define ADC_SQR1_SQ16_N(n) ((n) << 15) /**< @brief 16th channel in seq.*/
+/** @} */
+
+/**
+ * @name Sampling rate settings helper macros
+ * @{
+ */
+#define ADC_SMPR2_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */
+#define ADC_SMPR2_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */
+#define ADC_SMPR2_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */
+#define ADC_SMPR2_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */
+#define ADC_SMPR2_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */
+#define ADC_SMPR2_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */
+#define ADC_SMPR2_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */
+#define ADC_SMPR2_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */
+#define ADC_SMPR2_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */
+#define ADC_SMPR2_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */
+
+#define ADC_SMPR1_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */
+#define ADC_SMPR1_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */
+#define ADC_SMPR1_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */
+#define ADC_SMPR1_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */
+#define ADC_SMPR1_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */
+#define ADC_SMPR1_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */
+#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18) /**< @brief Temperature Sensor
+ sampling time. */
+#define ADC_SMPR1_SMP_VREF(n) ((n) << 21) /**< @brief Voltage Reference
+ sampling time. */
+#define ADC_SMPR1_SMP_VBAT(n) ((n) << 24) /**< @brief VBAT sampling time. */
+/** @} */
+
+/**
+ * @name Threshold settings helper macros
+ * @{
+ */
+/**
+ * @brief High threshold limitation.
+ */
+#define ADC_HTR(n) ((n > ADC_HTR_HT) ? ADC_HTR_HT : n)
+/**
+ * @brief Low threshold limitation.
+ */
+#define ADC_LTR(n) ((n > ADC_LTR_LT) ? ADC_LTR_LT : n)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD1;
+#endif
+
+#if STM32_ADC_USE_ADC2 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD2;
+#endif
+
+#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD3;
+#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 adcSTM32EnableTSVREFE(void);
+ void adcSTM32DisableTSVREFE(void);
+ void adcSTM32EnableVBATE(void);
+ void adcSTM32DisableVBATE(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ADC */
+
+#endif /* HAL_ADC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt new file mode 100644 index 0000000..a13d327 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv2/notes.txt @@ -0,0 +1,13 @@ +STM32 ADCv2 driver.
+
+Driver capability:
+
+- Supports the STM32 "advanced" ADC found on F2, F4 and F7 sub-families.
+
+The file registry must export:
+
+STM32_HAS_ADCx - ADCx presence flag (1..3).
+STM32_ADC_HANDLER - IRQ vector name for ADCs (shared).
+STM32_ADC_NUMBER - IRQ vector number for ADCs (shared).
+STM32_ADCx_DMA_MSK - Mask of the compatible DMA channels.
+STM32_ADCx_DMA_CHN - Mask of the channels mapping.
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk new file mode 100644 index 0000000..049021c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv3
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c new file mode 100644 index 0000000..8df21bf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.c @@ -0,0 +1,1009 @@ +/*
+ 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 ADCv3/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)
+
+#define ADC2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_CHN)
+
+#define ADC3_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_CHN)
+
+#define ADC4_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_ADC_ADC4_DMA_STREAM, STM32_ADC4_DMA_CHN)
+
+#if STM32_ADC_DUAL_MODE
+#if STM32_ADC_COMPACT_SAMPLES
+/* Compact type dual mode.*/
+#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD)
+#define ADC_DMA_MDMA ADC_CCR_MDMA_HWORD
+
+#else /* !STM32_ADC_COMPACT_SAMPLES */
+/* Large type dual mode.*/
+#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD)
+#define ADC_DMA_MDMA ADC_CCR_MDMA_WORD
+#endif /* !STM32_ADC_COMPACT_SAMPLES */
+
+#else /* !STM32_ADC_DUAL_MODE */
+#if STM32_ADC_COMPACT_SAMPLES
+/* Compact type single mode.*/
+#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_PSIZE_BYTE)
+#define ADC_DMA_MDMA ADC_CCR_MDMA_DISABLED
+
+#else /* !STM32_ADC_COMPACT_SAMPLES */
+/* Large type single mode.*/
+#define ADC_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD)
+#define ADC_DMA_MDMA ADC_CCR_MDMA_DISABLED
+#endif /* !STM32_ADC_COMPACT_SAMPLES */
+#endif /* !STM32_ADC_DUAL_MODE */
+
+/* Addressing header differences.*/
+#if !defined(ADC_IER_OVRIE)
+#define ADC_IER_OVRIE ADC_IER_OVR
+#endif
+
+#if !defined(ADC_IER_AWD1IE)
+#define ADC_IER_AWD1IE ADC_IER_AWD1
+#endif
+
+#if !defined(ADC_CR_ADVREGEN)
+#define ADC_CR_ADVREGEN ADC_CR_ADVREGEN_0
+#endif
+
+#if !defined(ADC_CR_DEEPPWD)
+#define ADC_CR_DEEPPWD ADC_CR_ADVREGEN_1
+#endif
+
+#if !defined(ADC_ISR_ADRDY)
+#define ADC_ISR_ADRDY ADC_ISR_ADRD
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief ADC1 driver identifier.*/
+#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__)
+ADCDriver ADCD1;
+#endif
+
+/** @brief ADC2 driver identifier.*/
+#if STM32_ADC_USE_ADC2 || defined(__DOXYGEN__)
+ADCDriver ADCD2;
+#endif
+
+/** @brief ADC3 driver identifier.*/
+#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__)
+ADCDriver ADCD3;
+#endif
+
+/** @brief ADC4 driver identifier.*/
+#if STM32_ADC_USE_ADC4 || defined(__DOXYGEN__)
+ADCDriver ADCD4;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const ADCConfig default_config = {
+ .difsel = 0
+};
+
+static uint32_t clkmask;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the ADC voltage regulator.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_vreg_on(ADCDriver *adcp) {
+
+ adcp->adcm->CR = 0; /* See RM.*/
+ adcp->adcm->CR = ADC_CR_ADVREGEN;
+#if STM32_ADC_DUAL_MODE
+ adcp->adcs->CR = ADC_CR_ADVREGEN;
+#endif
+ osalSysPolledDelayX(OSAL_US2RTC(STM32_HCLK, 20));
+}
+
+/**
+ * @brief Disables the ADC voltage regulator.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_vreg_off(ADCDriver *adcp) {
+
+ adcp->adcm->CR = 0; /* See RM.*/
+ adcp->adcm->CR = ADC_CR_DEEPPWD;
+#if STM32_ADC_DUAL_MODE
+ adcp->adcs->CR = 0;
+ adcp->adcs->CR = ADC_CR_DEEPPWD;
+#endif
+}
+
+/**
+ * @brief Calibrates and ADC unit.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_calibrate(ADCDriver *adcp) {
+
+ osalDbgAssert(adcp->adcm->CR == ADC_CR_ADVREGEN, "invalid register state");
+
+ /* Differential calibration for master ADC.*/
+ adcp->adcm->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF;
+ adcp->adcm->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF | ADC_CR_ADCAL;
+ while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0)
+ ;
+
+ /* Single-ended calibration for master ADC.*/
+ adcp->adcm->CR = ADC_CR_ADVREGEN;
+ adcp->adcm->CR = ADC_CR_ADVREGEN | ADC_CR_ADCAL;
+ while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0)
+ ;
+
+#if STM32_ADC_DUAL_MODE
+ osalDbgAssert(adcp->adcs->CR == ADC_CR_ADVREGEN, "invalid register state");
+
+ /* Differential calibration for slave ADC.*/
+ adcp->adcs->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF;
+ adcp->adcs->CR = ADC_CR_ADVREGEN | ADC_CR_ADCALDIF | ADC_CR_ADCAL;
+ while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0)
+ ;
+
+ /* Single-ended calibration for slave ADC.*/
+ adcp->adcs->CR = ADC_CR_ADVREGEN;
+ adcp->adcs->CR = ADC_CR_ADVREGEN | ADC_CR_ADCAL;
+ while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0)
+ ;
+#endif
+}
+
+/**
+ * @brief Enables the ADC analog circuit.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_analog_on(ADCDriver *adcp) {
+
+ adcp->adcm->CR |= ADC_CR_ADEN;
+ while ((adcp->adcm->ISR & ADC_ISR_ADRDY) == 0)
+ ;
+#if STM32_ADC_DUAL_MODE
+ adcp->adcs->CR |= ADC_CR_ADEN;
+ while ((adcp->adcs->ISR & ADC_ISR_ADRDY) == 0)
+ ;
+#endif
+}
+
+/**
+ * @brief Disables the ADC analog circuit.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_analog_off(ADCDriver *adcp) {
+
+ adcp->adcm->CR |= ADC_CR_ADDIS;
+ while ((adcp->adcm->CR & ADC_CR_ADDIS) != 0)
+ ;
+#if STM32_ADC_DUAL_MODE
+ adcp->adcs->CR |= ADC_CR_ADDIS;
+ while ((adcp->adcs->CR & ADC_CR_ADDIS) != 0)
+ ;
+#endif
+}
+
+/**
+ * @brief Stops an ongoing conversion, if any.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_stop_adc(ADCDriver *adcp) {
+
+ if (adcp->adcm->CR & ADC_CR_ADSTART) {
+ adcp->adcm->CR |= ADC_CR_ADSTP;
+ while (adcp->adcm->CR & ADC_CR_ADSTP)
+ ;
+ adcp->adcm->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_dma_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);
+ }
+ }
+ }
+}
+
+/**
+ * @brief ADC IRQ service routine.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] isr content of the ISR register
+ */
+static void adc_lld_serve_interrupt(ADCDriver *adcp, uint32_t 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 error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD1);
+ }
+ if (isr & ADC_ISR_AWD2) {
+ /* Analog watchdog error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD2);
+ }
+ if (isr & ADC_ISR_AWD3) {
+ /* Analog watchdog error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD3);
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2 || defined(__DOXYGEN__)
+/**
+ * @brief ADC1/ADC2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+#if STM32_ADC_DUAL_MODE
+
+ isr = ADC1->ISR;
+ isr |= ADC2->ISR;
+ ADC1->ISR = isr;
+ ADC2->ISR = isr;
+#if defined(STM32_ADC_ADC12_IRQ_HOOK)
+ STM32_ADC_ADC12_IRQ_HOOK
+#endif
+ adc_lld_serve_interrupt(&ADCD1, isr);
+
+#else /* !STM32_ADC_DUAL_MODE */
+
+#if STM32_ADC_USE_ADC1
+ isr = ADC1->ISR;
+ ADC1->ISR = isr;
+#if defined(STM32_ADC_ADC1_IRQ_HOOK)
+ STM32_ADC_ADC1_IRQ_HOOK
+#endif
+ adc_lld_serve_interrupt(&ADCD1, isr);
+#endif
+
+#if STM32_ADC_USE_ADC2
+ isr = ADC2->ISR;
+ ADC2->ISR = isr;
+#if defined(STM32_ADC_ADC2_IRQ_HOOK)
+ STM32_ADC_ADC2_IRQ_HOOK
+#endif
+ adc_lld_serve_interrupt(&ADCD2, isr);
+#endif
+
+#endif /* !STM32_ADC_DUAL_MODE */
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_ADC_USE_ADC1 */
+
+#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__)
+/**
+ * @brief ADC3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC3_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ isr = ADC3->ISR;
+ ADC3->ISR = isr;
+#if defined(STM32_ADC_ADC3_IRQ_HOOK)
+ STM32_ADC_ADC3_IRQ_HOOK
+#endif
+ adc_lld_serve_interrupt(&ADCD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if STM32_ADC_DUAL_MODE
+/**
+ * @brief ADC4 interrupt handler (as ADC3 slave).
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC4_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ isr = ADC4->ISR;
+ ADC4->ISR = isr;
+
+ adc_lld_serve_interrupt(&ADCD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_ADC_DUAL_MODE */
+#endif /* STM32_ADC_USE_ADC3 */
+
+#if STM32_ADC_USE_ADC4 || defined(__DOXYGEN__)
+/**
+ * @brief ADC4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC4_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ isr = ADC4->ISR;
+ ADC4->ISR = isr;
+
+ adc_lld_serve_interrupt(&ADCD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_ADC_USE_ADC4 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ADC driver initialization.
+ *
+ * @notapi
+ */
+void adc_lld_init(void) {
+
+ clkmask = 0;
+
+#if STM32_ADC_USE_ADC1
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD1);
+#if defined(ADC1_2_COMMON)
+ ADCD1.adcc = ADC1_2_COMMON;
+#elif defined(ADC12_COMMON)
+ ADCD1.adcc = ADC12_COMMON;
+#elif defined(ADC123_COMMON)
+ ADCD1.adcc = ADC123_COMMON;
+#else
+ ADCD1.adcc = ADC1_COMMON;
+#endif
+ ADCD1.adcm = ADC1;
+#if STM32_ADC_DUAL_MODE
+ ADCD1.adcs = ADC2;
+#endif
+ ADCD1.dmastp = NULL;
+ ADCD1.dmamode = ADC_DMA_SIZE |
+ STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+#endif /* STM32_ADC_USE_ADC1 */
+
+#if STM32_ADC_USE_ADC2
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD2);
+#if defined(ADC1_2_COMMON)
+ ADCD2.adcc = ADC1_2_COMMON;
+#elif defined(ADC12_COMMON)
+ ADCD2.adcc = ADC12_COMMON;
+#elif defined(ADC123_COMMON)
+ ADCD2.adcc = ADC123_COMMON;
+#endif
+ ADCD2.adcm = ADC2;
+ ADCD2.dmastp = NULL;
+ ADCD2.dmamode = ADC_DMA_SIZE |
+ STM32_DMA_CR_PL(STM32_ADC_ADC2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+#endif /* STM32_ADC_USE_ADC2 */
+
+#if STM32_ADC_USE_ADC3
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD3);
+#if defined(ADC3_4_COMMON)
+ ADCD3.adcc = ADC3_4_COMMON;
+#elif defined(ADC345_COMMON)
+ ADCD3.adcc = ADC345_COMMON;
+#elif defined(ADC123_COMMON)
+ ADCD3.adcc = ADC123_COMMON;
+#else
+ ADCD3.adcc = ADC3_COMMON;
+#endif
+ ADCD3.adcm = ADC3;
+#if STM32_ADC_DUAL_MODE
+ ADCD3.adcs = ADC4;
+#endif
+ ADCD3.dmastp = NULL;
+ 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;
+#endif /* STM32_ADC_USE_ADC3 */
+
+#if STM32_ADC_USE_ADC4
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD4);
+#if defined(ADC3_4_COMMON)
+ ADCD4.adcc = ADC3_4_COMMON;
+#elif defined(ADC345_COMMON)
+ ADCD4.adcc = ADC345_COMMON;
+#endif
+ ADCD4.adcm = ADC4;
+ ADCD4.dmastp = NULL;
+ ADCD4.dmamode = ADC_DMA_SIZE |
+ STM32_DMA_CR_PL(STM32_ADC_ADC4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+#endif /* STM32_ADC_USE_ADC4 */
+
+ /* IRQs setup.*/
+#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2
+ nvicEnableVector(STM32_ADC1_NUMBER, STM32_ADC_ADC12_IRQ_PRIORITY);
+#endif
+#if STM32_ADC_USE_ADC3
+ nvicEnableVector(STM32_ADC3_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY);
+#if STM32_ADC_DUAL_MODE
+ nvicEnableVector(STM32_ADC4_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY);
+#endif
+#endif
+#if STM32_ADC_USE_ADC4
+ nvicEnableVector(STM32_ADC4_NUMBER, STM32_ADC_ADC4_IRQ_PRIORITY);
+#endif
+
+ /* ADC units pre-initializations.*/
+#if defined(STM32F3XX)
+#if STM32_HAS_ADC1 && STM32_HAS_ADC2
+#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2
+ rccEnableADC12(true);
+ rccResetADC12();
+ ADC1_2_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA;
+ rccDisableADC12();
+#endif
+#else
+#if STM32_ADC_USE_ADC1
+ rccEnableADC12(true);
+ rccResetADC12();
+ ADC1_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA;
+ rccDisableADC12();
+#endif
+#endif
+#if STM32_ADC_USE_ADC3 || STM32_ADC_USE_ADC4
+ rccEnableADC34(true);
+ rccResetADC34();
+ ADC3_4_COMMON->CCR = STM32_ADC_ADC34_CLOCK_MODE | ADC_DMA_MDMA;
+ rccDisableADC34();
+#endif
+#endif
+
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+ rccEnableADC123(true);
+ rccResetADC123();
+#if defined(ADC1_2_COMMON)
+ ADC1_2_COMMON->CCR = STM32_ADC_ADC123_PRESC | STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA;
+#elif defined(ADC123_COMMON)
+ ADC123_COMMON->CCR = STM32_ADC_ADC123_PRESC | STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA;
+#else
+ ADC1_COMMON->CCR = STM32_ADC_ADC123_PRESC | STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA;
+#endif
+
+ rccDisableADC123();
+#endif
+
+#if defined(STM32G4XX)
+#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2
+ rccEnableADC12(true);
+ rccResetADC12();
+ ADC12_COMMON->CCR = STM32_ADC_ADC12_PRESC | STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA;
+ rccDisableADC12();
+#endif
+#if STM32_ADC_USE_ADC3 || STM32_ADC_USE_ADC4
+ rccEnableADC345(true);
+ rccResetADC345();
+ ADC345_COMMON->CCR = STM32_ADC_ADC345_PRESC | STM32_ADC_ADC345_CLOCK_MODE | ADC_DMA_MDMA;
+ rccDisableADC345();
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the ADC peripheral.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @notapi
+ */
+void adc_lld_start(ADCDriver *adcp) {
+
+ /* Handling the default configuration.*/
+ if (adcp->config == NULL) {
+ adcp->config = &default_config;
+ }
+
+ /* 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_dma_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
+
+ clkmask |= (1 << 0);
+#if defined(STM32F3XX) || defined(STM32G4XX)
+ rccEnableADC12(true);
+#endif
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+ rccEnableADC123(true);
+#endif
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC1);
+#endif
+ }
+#endif /* STM32_ADC_USE_ADC1 */
+
+#if STM32_ADC_USE_ADC2
+ if (&ADCD2 == adcp) {
+ adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC2_DMA_STREAM,
+ STM32_ADC_ADC2_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_dma_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
+
+ clkmask |= (1 << 1);
+#if defined(STM32F3XX) || defined(STM32G4XX)
+ rccEnableADC12(true);
+#endif
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+ rccEnableADC123(true);
+#endif
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC2);
+#endif
+ }
+#endif /* STM32_ADC_USE_ADC2 */
+
+#if STM32_ADC_USE_ADC3
+ if (&ADCD3 == adcp) {
+ adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC3_DMA_STREAM,
+ STM32_ADC_ADC3_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_dma_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
+
+ clkmask |= (1 << 2);
+#if defined(STM32F3XX)
+ rccEnableADC34(true);
+#endif
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+ rccEnableADC123(true);
+#endif
+#if defined(STM32G4XX)
+ rccEnableADC345(true);
+#endif
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC3);
+#endif
+ }
+#endif /* STM32_ADC_USE_ADC3 */
+
+#if STM32_ADC_USE_ADC4
+ if (&ADCD4 == adcp) {
+ adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC4_DMA_STREAM,
+ STM32_ADC_ADC4_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_dma_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
+
+ clkmask |= (1 << 3);
+#if defined(STM32F3XX)
+ rccEnableADC34(true);
+#endif
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+ rccEnableADC123(true);
+#endif
+#if defined(STM32G4XX)
+ rccEnableADC345(true);
+#endif
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC4);
+#endif
+ }
+#endif /* STM32_ADC_USE_ADC4 */
+
+ /* Setting DMA peripheral-side pointer.*/
+#if STM32_ADC_DUAL_MODE
+ dmaStreamSetPeripheral(adcp->dmastp, &adcp->adcc->CDR);
+#else
+ dmaStreamSetPeripheral(adcp->dmastp, &adcp->adcm->DR);
+#endif
+
+ /* Differential channels setting.*/
+#if STM32_ADC_DUAL_MODE
+ adcp->adcm->DIFSEL = adcp->config->difsel;
+ adcp->adcs->DIFSEL = adcp->config->difsel;
+#else
+ adcp->adcm->DIFSEL = adcp->config->difsel;
+#endif
+
+ /* Master ADC calibration.*/
+ adc_lld_vreg_on(adcp);
+ adc_lld_calibrate(adcp);
+
+ /* Master ADC enabled here in order to reduce conversions latencies.*/
+ adc_lld_analog_on(adcp);
+ }
+}
+
+/**
+ * @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) {
+
+ /* Releasing the associated DMA channel.*/
+ dmaStreamFreeI(adcp->dmastp);
+ adcp->dmastp = NULL;
+
+ /* Stopping the ongoing conversion, if any.*/
+ adc_lld_stop_adc(adcp);
+
+ /* Disabling ADC analog circuit and regulator.*/
+ adc_lld_analog_off(adcp);
+ adc_lld_vreg_off(adcp);
+
+#if STM32_ADC_USE_ADC1
+ if (&ADCD1 == adcp) {
+ /* Resetting CCR options except default ones.*/
+ clkmask &= ~(1 << 0);
+ }
+#endif
+
+#if STM32_ADC_USE_ADC2
+ if (&ADCD2 == adcp) {
+ clkmask &= ~(1 << 1);
+ }
+#endif
+
+#if STM32_ADC_USE_ADC3
+ if (&ADCD3 == adcp) {
+ clkmask &= ~(1 << 2);
+ }
+#endif
+
+#if STM32_ADC_USE_ADC4
+ if (&ADCD4 == adcp) {
+ clkmask &= ~(1 << 3);
+ }
+#endif
+
+#if defined(STM32F3XX)
+#if STM32_HAS_ADC1 || STM32_HAS_ADC2
+ if ((clkmask & 0x3) == 0) {
+ rccDisableADC12();
+ }
+#endif
+
+#if STM32_HAS_ADC3 || STM32_HAS_ADC4
+ if ((clkmask & 0xC) == 0) {
+ rccDisableADC34();
+ }
+#endif
+#endif
+
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+ if ((clkmask & 0x7) == 0) {
+ rccDisableADC123();
+ }
+#endif
+
+#if defined(STM32G4XX)
+#if STM32_HAS_ADC1 || STM32_HAS_ADC2
+ if ((clkmask & 0x3) == 0) {
+ rccDisableADC12();
+ }
+#endif
+
+#if STM32_HAS_ADC3 || STM32_HAS_ADC4
+ if ((clkmask & 0xC) == 0) {
+ rccDisableADC345();
+ }
+#endif
+#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 dmamode, cfgr;
+ const ADCConversionGroup *grpp = adcp->grpp;
+#if STM32_ADC_DUAL_MODE
+ uint32_t ccr = grpp->ccr & ~(ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK);
+#endif
+
+ osalDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0),
+ "odd number of channels in dual mode");
+
+ /* Calculating control registers values.*/
+ dmamode = adcp->dmamode;
+ cfgr = grpp->cfgr | ADC_CFGR_DMAEN;
+ if (grpp->circular) {
+ dmamode |= STM32_DMA_CR_CIRC;
+#if STM32_ADC_DUAL_MODE
+ ccr |= ADC_CCR_DMACFG_CIRCULAR;
+#else
+ cfgr |= ADC_CFGR_DMACFG_CIRCULAR;
+#endif
+ if (adcp->depth > 1) {
+ /* If circular buffer depth > 1, then the half transfer interrupt
+ is enabled in order to allow streaming processing.*/
+ dmamode |= STM32_DMA_CR_HTIE;
+ }
+ }
+
+ /* DMA setup.*/
+ dmaStreamSetMemory0(adcp->dmastp, adcp->samples);
+#if STM32_ADC_DUAL_MODE
+ dmaStreamSetTransactionSize(adcp->dmastp, ((uint32_t)grpp->num_channels/2) *
+ (uint32_t)adcp->depth);
+#else
+ dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels *
+ (uint32_t)adcp->depth);
+#endif
+ dmaStreamSetMode(adcp->dmastp, dmamode);
+ dmaStreamEnable(adcp->dmastp);
+
+ /* ADC setup, if it is defined a callback for the analog watch dog then it
+ is enabled.*/
+ adcp->adcm->ISR = adcp->adcm->ISR;
+ if (grpp->error_cb != NULL) {
+ adcp->adcm->IER = ADC_IER_OVRIE | ADC_IER_AWD1IE
+ | ADC_IER_AWD2IE
+ | ADC_IER_AWD3IE;
+ adcp->adcm->TR1 = grpp->tr1;
+ adcp->adcm->TR2 = grpp->tr2;
+ adcp->adcm->TR3 = grpp->tr3;
+ adcp->adcm->AWD2CR = grpp->awd2cr;
+ adcp->adcm->AWD3CR = grpp->awd3cr;
+ }
+
+#if STM32_ADC_DUAL_MODE
+
+ /* Configuring the CCR register with the user-specified settings
+ in the conversion group configuration structure, static settings are
+ preserved.*/
+ adcp->adcc->CCR = (adcp->adcc->CCR &
+ (ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK)) | ccr;
+
+ adcp->adcm->SMPR1 = grpp->smpr[0];
+ adcp->adcm->SMPR2 = grpp->smpr[1];
+ adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
+ adcp->adcm->SQR2 = grpp->sqr[1];
+ adcp->adcm->SQR3 = grpp->sqr[2];
+ adcp->adcm->SQR4 = grpp->sqr[3];
+ adcp->adcs->SMPR1 = grpp->ssmpr[0];
+ adcp->adcs->SMPR2 = grpp->ssmpr[1];
+ adcp->adcs->SQR1 = grpp->ssqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
+ adcp->adcs->SQR2 = grpp->ssqr[1];
+ adcp->adcs->SQR3 = grpp->ssqr[2];
+ adcp->adcs->SQR4 = grpp->ssqr[3];
+
+#else /* !STM32_ADC_DUAL_MODE */
+ adcp->adcm->SMPR1 = grpp->smpr[0];
+ adcp->adcm->SMPR2 = grpp->smpr[1];
+ adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels);
+ adcp->adcm->SQR2 = grpp->sqr[1];
+ adcp->adcm->SQR3 = grpp->sqr[2];
+ adcp->adcm->SQR4 = grpp->sqr[3];
+#endif /* !STM32_ADC_DUAL_MODE */
+
+ /* ADC configuration.*/
+ adcp->adcm->CFGR = cfgr;
+#if (STM32_ADCV3_OVERSAMPLING == TRUE) || defined(__DOXYGEN__)
+ adcp->adcm->CFGR2 = grpp->cfgr2;
+#endif
+
+ /* Starting conversion.*/
+ adcp->adcm->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);
+}
+
+/**
+ * @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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->CCR &= ~ADC_CCR_TSEN;
+}
+
+/**
+ * @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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->CCR &= ~ADC_CCR_VBATEN;
+}
+
+#endif /* HAL_USE_ADC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h new file mode 100644 index 0000000..8d6c615 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/hal_adc_lld.h @@ -0,0 +1,1026 @@ +/*
+ 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 ADCv3/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 Available analog channels
+ * @{
+ */
+#define ADC_CHANNEL_IN0 0 /**< @brief External analog input 0. */
+#define ADC_CHANNEL_IN1 1 /**< @brief External analog input 1. */
+#define ADC_CHANNEL_IN2 2 /**< @brief External analog input 2. */
+#define ADC_CHANNEL_IN3 3 /**< @brief External analog input 3. */
+#define ADC_CHANNEL_IN4 4 /**< @brief External analog input 4. */
+#define ADC_CHANNEL_IN5 5 /**< @brief External analog input 5. */
+#define ADC_CHANNEL_IN6 6 /**< @brief External analog input 6. */
+#define ADC_CHANNEL_IN7 7 /**< @brief External analog input 7. */
+#define ADC_CHANNEL_IN8 8 /**< @brief External analog input 8. */
+#define ADC_CHANNEL_IN9 9 /**< @brief External analog input 9. */
+#define ADC_CHANNEL_IN10 10 /**< @brief External analog input 10. */
+#define ADC_CHANNEL_IN11 11 /**< @brief External analog input 11. */
+#define ADC_CHANNEL_IN12 12 /**< @brief External analog input 12. */
+#define ADC_CHANNEL_IN13 13 /**< @brief External analog input 13. */
+#define ADC_CHANNEL_IN14 14 /**< @brief External analog input 14. */
+#define ADC_CHANNEL_IN15 15 /**< @brief External analog input 15. */
+#define ADC_CHANNEL_IN16 16 /**< @brief External analog input 16. */
+#define ADC_CHANNEL_IN17 17 /**< @brief External analog input 17. */
+#define ADC_CHANNEL_IN18 18 /**< @brief External analog input 18. */
+/** @} */
+
+/**
+ * @name Sampling rates
+ * @{
+ */
+#if defined(STM32F3XX) || defined(__DOXYGEN__)
+#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. */
+#endif
+#if defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ADC_SMPR_SMP_2P5 0 /**< @brief 15 cycles conversion time */
+#define ADC_SMPR_SMP_6P5 1 /**< @brief 19 cycles conversion time. */
+#define ADC_SMPR_SMP_12P5 2 /**< @brief 25 cycles conversion time. */
+#define ADC_SMPR_SMP_24P5 3 /**< @brief 37 cycles conversion time. */
+#define ADC_SMPR_SMP_47P5 4 /**< @brief 60 cycles conversion time. */
+#define ADC_SMPR_SMP_92P5 5 /**< @brief 105 cycles conversion time. */
+#define ADC_SMPR_SMP_247P5 6 /**< @brief 260 cycles conversion time. */
+#define ADC_SMPR_SMP_640P5 7 /**< @brief 653 cycles conversion time. */
+#endif
+/** @} */
+
+/**
+ * @name CFGR register configuration helpers
+ * @{
+ */
+#define ADC_CFGR_DMACFG_MASK (1 << 1)
+#define ADC_CFGR_DMACFG_ONESHOT (0 << 1)
+#define ADC_CFGR_DMACFG_CIRCULAR (1 << 1)
+
+#define ADC_CFGR_RES_MASK (3 << 3)
+#define ADC_CFGR_RES_12BITS (0 << 3)
+#define ADC_CFGR_RES_10BITS (1 << 3)
+#define ADC_CFGR_RES_8BITS (2 << 3)
+#define ADC_CFGR_RES_6BITS (3 << 3)
+
+#if defined(STM32F3XX) || defined(STM32L4XX) || defined(STM32L4XXP) || \
+ defined(__DOXYGEN__)
+#define ADC_CFGR_ALIGN_MASK (1 << 5)
+#define ADC_CFGR_ALIGN_RIGHT (0 << 5)
+#define ADC_CFGR_ALIGN_LEFT (1 << 5)
+
+#define ADC_CFGR_EXTSEL_MASK (15 << 6)
+#define ADC_CFGR_EXTSEL_SRC(n) ((n) << 6)
+#endif
+#if defined(STM32G4XX)
+#define ADC_CFGR_ALIGN_MASK (1 << 15)
+#define ADC_CFGR_ALIGN_RIGHT (0 << 15)
+#define ADC_CFGR_ALIGN_LEFT (1 << 15)
+
+#define ADC_CFGR_EXTSEL_MASK (31 << 5)
+#define ADC_CFGR_EXTSEL_SRC(n) ((n) << 5)
+#endif
+
+#define ADC_CFGR_EXTEN_MASK (3 << 10)
+#define ADC_CFGR_EXTEN_DISABLED (0 << 10)
+#define ADC_CFGR_EXTEN_RISING (1 << 10)
+#define ADC_CFGR_EXTEN_FALLING (2 << 10)
+#define ADC_CFGR_EXTEN_BOTH (3 << 10)
+
+#define ADC_CFGR_DISCEN_MASK (1 << 16)
+#define ADC_CFGR_DISCEN_DISABLED (0 << 16)
+#define ADC_CFGR_DISCEN_ENABLED (1 << 16)
+
+#define ADC_CFGR_DISCNUM_MASK (7 << 17)
+#define ADC_CFGR_DISCNUM_VAL(n) ((n) << 17)
+
+#define ADC_CFGR_AWD1_DISABLED 0
+#define ADC_CFGR_AWD1_ALL (1 << 23)
+#define ADC_CFGR_AWD1_SINGLE(n) (((n) << 26) | (1 << 23) | (1 << 22))
+/** @} */
+
+/**
+ * @name CCR register configuration helpers
+ * @{
+ */
+#define ADC_CCR_DUAL_MASK (31 << 0)
+#define ADC_CCR_DUAL_FIELD(n) ((n) << 0)
+
+#define ADC_CCR_DELAY_MASK (15 << 8)
+#define ADC_CCR_DELAY_FIELD(n) ((n) << 8)
+
+#define ADC_CCR_DMACFG_MASK (1 << 13)
+#define ADC_CCR_DMACFG_ONESHOT (0 << 13)
+#define ADC_CCR_DMACFG_CIRCULAR (1 << 13)
+
+#define ADC_CCR_MDMA_MASK (3 << 14)
+#define ADC_CCR_MDMA_DISABLED (0 << 14)
+#define ADC_CCR_MDMA_WORD (2 << 14)
+#define ADC_CCR_MDMA_HWORD (3 << 14)
+
+#define ADC_CCR_CKMODE_MASK (3 << 16)
+#define ADC_CCR_CKMODE_ADCCK (0 << 16)
+#define ADC_CCR_CKMODE_AHB_DIV1 (1 << 16)
+#define ADC_CCR_CKMODE_AHB_DIV2 (2 << 16)
+#define ADC_CCR_CKMODE_AHB_DIV4 (3 << 16)
+
+#if !defined(STM32F3XX)
+#define ADC_CCR_PRESC_MASK (15 << 18)
+#define ADC_CCR_PRESC_NOCLOCK (0 << 18)
+#define ADC_CCR_PRESC_DIV2 (1 << 18)
+#define ADC_CCR_PRESC_DIV4 (2 << 18)
+#define ADC_CCR_PRESC_DIV6 (3 << 18)
+#define ADC_CCR_PRESC_DIV8 (4 << 18)
+#define ADC_CCR_PRESC_DIV10 (5 << 18)
+#define ADC_CCR_PRESC_DIV12 (6 << 18)
+#define ADC_CCR_PRESC_DIV16 (7 << 18)
+#define ADC_CCR_PRESC_DIV32 (8 << 18)
+#define ADC_CCR_PRESC_DIV64 (9 << 18)
+#define ADC_CCR_PRESC_DIV128 (10 << 18)
+#define ADC_CCR_PRESC_DIV256 (11 << 18)
+#endif /* !defined(STM32F3XX) */
+
+/* F3 headers do not define the following macros, L4 headers do.*/
+#if !defined(ADC_CCR_VREFEN) || defined(__DOXYGEN__)
+#define ADC_CCR_VREFEN (1 << 22)
+#endif
+
+#if !defined(ADC_CCR_TSEN) || defined(__DOXYGEN__)
+#define ADC_CCR_TSEN (1 << 23)
+#endif
+
+#if !defined(ADC_CCR_VBATEN) || defined(__DOXYGEN__)
+#define ADC_CCR_VBATEN (1 << 24)
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Enables the ADC master/slave mode.
+ * @note In dual mode only ADCD1 and ADCD3 are available.
+ */
+#if !defined(STM32_ADC_DUAL_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_DUAL_MODE FALSE
+#endif
+
+/**
+ * @brief Makes the ADC samples type an 8bits one.
+ * @note 10 and 12 bits sampling mode must not be used when this option
+ * is enabled.
+ */
+#if !defined(STM32_ADC_COMPACT_SAMPLES) || defined(__DOXYGEN__)
+#define STM32_ADC_COMPACT_SAMPLES FALSE
+#endif
+
+/**
+ * @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 ADC2 driver enable switch.
+ * @details If set to @p TRUE the support for ADC2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ADC_USE_ADC2) || defined(__DOXYGEN__)
+#define STM32_ADC_USE_ADC2 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 ADC4 driver enable switch.
+ * @details If set to @p TRUE the support for ADC4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ADC_USE_ADC4) || defined(__DOXYGEN__)
+#define STM32_ADC_USE_ADC4 FALSE
+#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 ADC2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_ADC_ADC2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief ADC3 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief ADC4 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_ADC_ADC4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC4_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 5
+#endif
+
+/**
+ * @brief ADC3 interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_IRQ_PRIORITY 5
+#endif
+
+/**
+ * @brief ADC4 interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC4_IRQ_PRIORITY 5
+#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 5
+#endif
+
+/**
+ * @brief ADC2 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 5
+#endif
+
+/**
+ * @brief ADC3 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 5
+#endif
+
+/**
+ * @brief ADC4 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC4_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC4_DMA_IRQ_PRIORITY 5
+#endif
+
+#if defined(STM32F3XX) || defined(__DOXYGEN__)
+/**
+ * @brief ADC1/ADC2 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC12_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV1
+#endif
+
+/**
+ * @brief ADC3/ADC4 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC34_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC34_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV1
+#endif
+#endif /* defined(STM32F3XX) */
+
+#if defined(STM32L4XX) || defined(STM32L4XXP) || defined(__DOXYGEN__)
+/**
+ * @brief ADC1/ADC2/ADC3 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC123_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC123_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV1
+#endif
+
+/**
+ * @brief ADC1/ADC2/ADC3 clock prescaler.
+ */
+#if !defined(STM32_ADC_ADC123_PRESC) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC123_PRESC ADC_CCR_PRESC_DIV2
+#endif
+#endif /* defined(STM32L4XX) || defined(STM32L4XXP) */
+
+#if defined(STM32G4XX) || defined(__DOXYGEN__)
+/**
+ * @brief ADC1/ADC2 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC12_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4
+#endif
+
+/**
+ * @brief ADC3/ADC4/ADC5 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC345_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC345_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4
+#endif
+
+/**
+ * @brief ADC1/ADC2 clock prescaler.
+ */
+#if !defined(STM32_ADC_ADC12_PRESC) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC12_PRESC ADC_CCR_PRESC_DIV2
+#endif
+
+/**
+ * @brief ADC3/ADC4/ADC5 clock prescaler.
+ */
+#if !defined(STM32_ADC_ADC345_PRESC) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC345_PRESC ADC_CCR_PRESC_DIV2
+#endif
+#endif /* defined(STM32G4XX) */
+
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Supported devices checks.*/
+#if !defined(STM32F3XX) && !defined(STM32L4XX) && !defined(STM32L4XXP) && \
+ !defined(STM32G4XX)
+#error "ADCv3 only supports F3, L4, L4+ and G4 STM32 devices"
+#endif
+
+#if defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX) || \
+ defined(__DOXYGEN__)
+#define STM32_ADCV3_OVERSAMPLING TRUE
+#else
+#define STM32_ADCV3_OVERSAMPLING FALSE
+#endif
+
+/* Registry checks.*/
+#if !defined(STM32_HAS_ADC1) || !defined(STM32_HAS_ADC2) || \
+ !defined(STM32_HAS_ADC3) || !defined(STM32_HAS_ADC4)
+#error "STM32_HAS_ADCx not defined in registry"
+#endif
+
+#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_HANDLER)) || \
+ (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_HANDLER)) || \
+ (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_HANDLER)) || \
+ (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_HANDLER))
+#error "STM32_ADCx_HANDLER not defined in registry"
+#endif
+
+#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_NUMBER)) || \
+ (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_NUMBER)) || \
+ (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_NUMBER)) || \
+ (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_NUMBER))
+#error "STM32_ADCx_NUMBER not defined in registry"
+#endif
+
+#if !STM32_DMA_SUPPORTS_DMAMUX
+#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_DMA_MSK)) || \
+ (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_DMA_MSK)) || \
+ (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_DMA_MSK)) || \
+ (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_DMA_MSK))
+#error "STM32_ADCx_DMA_MSK not defined in registry"
+#endif
+
+#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_DMA_CHN)) || \
+ (STM32_ADC_USE_ADC2 && !defined(STM32_ADC2_DMA_CHN)) || \
+ (STM32_ADC_USE_ADC3 && !defined(STM32_ADC3_DMA_CHN)) || \
+ (STM32_ADC_USE_ADC4 && !defined(STM32_ADC4_DMA_CHN))
+#error "STM32_ADCx_DMA_CHN not defined in registry"
+#endif
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* Units checks.*/
+#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1
+#error "ADC1 not present in the selected device"
+#endif
+
+#if STM32_ADC_USE_ADC2 && !STM32_HAS_ADC2
+#error "ADC2 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_ADC4 && !STM32_HAS_ADC4
+#error "ADC4 not present in the selected device"
+#endif
+
+/* Units checks related to dual mode.*/
+#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC1 && !STM32_HAS_ADC2
+#error "ADC2 not present in the selected device, required for dual mode"
+#endif
+
+#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC3 && !STM32_HAS_ADC4
+#error "ADC4 not present in the selected device, required for dual mode"
+#endif
+
+#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC2
+#error "ADC2 cannot be used in dual mode"
+#endif
+
+#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC4
+#error "ADC4 cannot be used in dual mode"
+#endif
+
+/* At least one ADC must be assigned.*/
+#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && \
+ !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4
+#error "ADC driver activated but no ADC peripheral assigned"
+#endif
+
+/* ISR arrangements checks.*/
+#if STM32_HAS_ADC1 && STM32_HAS_ADC2
+#if STM32_ADC1_NUMBER != STM32_ADC2_NUMBER
+#error "ADCv3 driver expects STM32_ADC1_NUMBER == STM32_ADC2_NUMBER from registry"
+#endif
+#endif
+
+/* ADC IRQ priority tests.*/
+#if STM32_ADC_USE_ADC1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC1"
+#endif
+
+#if STM32_ADC_USE_ADC2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC2"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC3"
+#endif
+
+#if STM32_ADC_USE_ADC4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC4"
+#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
+
+#if STM32_ADC_USE_ADC2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC2_DMA_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC2 DMA"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_DMA_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC3 DMA"
+#endif
+
+#if STM32_ADC_USE_ADC4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC4_DMA_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC4 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
+
+#if STM32_ADC_USE_ADC2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to ADC2"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to ADC3"
+#endif
+
+#if STM32_ADC_USE_ADC4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to ADC4"
+#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 "ADC1 DMA stream not defined"
+#endif
+
+#if STM32_ADC_USE_ADC2 && !defined(STM32_ADC_ADC2_DMA_STREAM)
+#error "ADC2 DMA stream not defined"
+#endif
+
+#if STM32_ADC_USE_ADC3 && !defined(STM32_ADC_ADC3_DMA_STREAM)
+#error "ADC3 DMA stream not defined"
+#endif
+
+#if STM32_ADC_USE_ADC4 && !defined(STM32_ADC_ADC4_DMA_STREAM)
+#error "ADC4 DMA stream not defined"
+#endif
+
+#if STM32_DMA_SUPPORTS_DMAMUX
+
+#else /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_ADC_USE_ADC1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK)
+#error "invalid DMA stream associated to ADC1"
+#endif
+
+#if STM32_ADC_USE_ADC2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_MSK)
+#error "invalid DMA stream associated to ADC2"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_MSK)
+#error "invalid DMA stream associated to ADC3"
+#endif
+
+#if STM32_ADC_USE_ADC4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_ADC_ADC4_DMA_STREAM, STM32_ADC4_DMA_MSK)
+#error "invalid DMA stream associated to ADC4"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* ADC clock prescaler checks.*/
+#if defined(STM32F3XX)
+#endif /* defined(STM32F3XX) */
+
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+#if STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV2
+#define ADC123_PRESC_VALUE 2
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV4
+#define ADC123_PRESC_VALUE 4
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV6
+#define ADC123_PRESC_VALUE 6
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV8
+#define ADC123_PRESC_VALUE 8
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV10
+#define ADC123_PRESC_VALUE 10
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV12
+#define ADC123_PRESC_VALUE 12
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV16
+#define ADC123_PRESC_VALUE 16
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV32
+#define ADC123_PRESC_VALUE 32
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV64
+#define ADC123_PRESC_VALUE 64
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV128
+#define ADC123_PRESC_VALUE 128
+#elif STM32_ADC_ADC123_PRESC == ADC_CCR_PRESC_DIV256
+#define ADC123_PRESC_VALUE 256
+#error "invalid clock divider selected for STM32_ADC_ADC12_PRESC"
+#endif
+#endif /* defined(STM32L4XX) || defined(STM32L4XXP) */
+
+#if defined(STM32G4XX)
+#if STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV2
+#define ADC12_PRESC_VALUE 2
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV4
+#define ADC12_PRESC_VALUE 4
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV6
+#define ADC12_PRESC_VALUE 6
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV8
+#define ADC12_PRESC_VALUE 8
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV10
+#define ADC12_PRESC_VALUE 10
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV12
+#define ADC12_PRESC_VALUE 12
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV16
+#define ADC12_PRESC_VALUE 16
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV32
+#define ADC12_PRESC_VALUE 32
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV64
+#define ADC12_PRESC_VALUE 64
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV128
+#define ADC12_PRESC_VALUE 128
+#elif STM32_ADC_ADC12_PRESC == ADC_CCR_PRESC_DIV256
+#define ADC12_PRESC_VALUE 256
+#error "invalid clock divider selected for STM32_ADC_ADC12_PRESC"
+#endif
+
+#if STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV2
+#define ADC345_PRESC_VALUE 2
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV4
+#define ADC345_PRESC_VALUE 4
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV6
+#define ADC345_PRESC_VALUE 6
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV8
+#define ADC345_PRESC_VALUE 8
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV10
+#define ADC345_PRESC_VALUE 10
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV12
+#define ADC345_PRESC_VALUE 12
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV16
+#define ADC345_PRESC_VALUE 16
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV32
+#define ADC345_PRESC_VALUE 32
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV64
+#define ADC345_PRESC_VALUE 64
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV128
+#define ADC345_PRESC_VALUE 128
+#elif STM32_ADC_ADC345_PRESC == ADC_CCR_PRESC_DIV256
+#define ADC345_PRESC_VALUE 256
+#error "invalid clock divider selected for STM32_ADC_ADC345_PRESC"
+#endif
+#endif /* defined(STM32G4XX) */
+
+/* ADC clock source checks.*/
+#if defined(STM32F3XX)
+#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC12_CLOCK STM32_ADC12CLK
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC12_CLOCK (STM32_HCLK / 1)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC12_CLOCK (STM32_HCLK / 2)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC12_CLOCK (STM32_HCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE"
+#endif
+
+#if STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC34_CLOCK STM32_ADC34CLK
+#elif STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC34_CLOCK (STM32_HCLK / 1)
+#elif STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC34_CLOCK (STM32_HCLK / 2)
+#elif STM32_ADC_ADC34_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC34_CLOCK (STM32_HCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC34_CLOCK_MODE"
+#endif
+
+#if STM32_ADC12_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC12_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+
+#if STM32_ADC34_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC34_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+#endif /* defined(STM32F3XX) */
+
+#if defined(STM32L4XX) || defined(STM32L4XXP)
+#if STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC123_CLOCK (STM32_ADCCLK / ADC123_PRESC_VALUE)
+#elif STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC123_CLOCK (STM32_ADCCLK / 1)
+#elif STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC123_CLOCK (STM32_ADCCLK / 2)
+#elif STM32_ADC_ADC123_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC123_CLOCK (STM32_ADCCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC123_CLOCK_MODE"
+#endif
+
+#if STM32_ADC123_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC123_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+#endif /* defined(STM32L4XX) || defined(STM32L4XXP) */
+
+#if defined(STM32G4XX)
+#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC12_CLOCK (STM32_ADC12CLK / ADC12_PRESC_VALUE)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC12_CLOCK (STM32_HCLK / 1)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC12_CLOCK (STM32_HCLK / 2)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC12_CLOCK (STM32_HCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE"
+#endif
+
+#if STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC345_CLOCK (STM32_ADC345CLK / ADC345_PRESC_VALUE)
+#elif STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC345_CLOCK (STM32_HCLK / 1)
+#elif STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC345_CLOCK (STM32_HCLK / 2)
+#elif STM32_ADC_ADC345_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC345_CLOCK (STM32_HCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC345_CLOCK_MODE"
+#endif
+
+#if STM32_ADC12_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC12_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+
+#if STM32_ADC345_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC345_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+#endif /* defined(STM32G4XX) */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief ADC sample data type.
+ */
+#if !STM32_ADC_COMPACT_SAMPLES || defined(__DOXYGEN__)
+typedef uint16_t adcsample_t;
+#else
+typedef uint8_t adcsample_t;
+#endif
+
+/**
+ * @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, /**< Watchdog 1 triggered. */
+ ADC_ERR_AWD2 = 3, /**< Watchdog 2 triggered. */
+ ADC_ERR_AWD3 = 4 /**< Watchdog 3 triggered. */
+} adcerror_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.*/ \
+ const stm32_dma_stream_t *dmastp; \
+ /* 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.*/ \
+ const stm32_dma_stream_t *dmastp; \
+ /* 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
+
+/**
+ * @brief Low level fields of the ADC group configuration structure.
+ */
+#if (STM32_ADCV3_OVERSAMPLING == TRUE) || defined(__DOXYGEN__)
+#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.*/ \
+ 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 AWD2CR register initialization data.*/ \
+ uint32_t awd2cr; \
+ /* ADC AWD3CR register initialization data.*/ \
+ uint32_t awd3cr; \
+ /* ADC CCR register initialization data. \
+ NOTE: Put this field to zero if not using oversampling.*/ \
+ uint32_t ccr; \
+ /* 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 tr1; \
+ uint32_t tr2; \
+ uint32_t tr3; \
+ uint32_t awd2cr; \
+ uint32_t awd3cr; \
+ uint32_t smpr[2]; \
+ uint32_t sqr[4]
+#endif /* STM32_ADC_DUAL_MODE == FALSE */
+
+#else /* STM32_ADCV3_OVERSAMPLING == FALSE */
+#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__)
+#define adc_lld_configuration_group_fields \
+ uint32_t cfgr; \
+ uint32_t tr1; \
+ uint32_t tr2; \
+ uint32_t tr3; \
+ uint32_t awd2cr; \
+ uint32_t awd3cr; \
+ uint32_t ccr; \
+ uint32_t smpr[2]; \
+ uint32_t sqr[4]; \
+ uint32_t ssmpr[2]; \
+ uint32_t ssqr[4]
+#else /* STM32_ADC_DUAL_MODE == FALSE */
+#define adc_lld_configuration_group_fields \
+ uint32_t cfgr; \
+ uint32_t tr1; \
+ uint32_t tr2; \
+ uint32_t tr3; \
+ uint32_t awd2cr; \
+ uint32_t awd3cr; \
+ uint32_t smpr[2]; \
+ uint32_t sqr[4]
+#endif /* STM32_ADC_DUAL_MODE == FALSE */
+#endif /* STM32_ADCV3_OVERSAMPLING == FALSE */
+
+/**
+ * @name Threshold registers initializers
+ * @{
+ */
+#define ADC_TR(low, high) (((uint32_t)(high) << 16) | (uint32_t)(low))
+#define ADC_TR_DISABLED ADC_TR(0U, 0x0FFFU)
+#define ADC_AWDCR_ENABLE(n) (1U << (n))
+/** @} */
+
+/**
+ * @name Sequences building helper macros
+ * @{
+ */
+/**
+ * @brief Number of channels in a conversion sequence.
+ */
+#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 0)
+
+#define ADC_SQR1_SQ1_N(n) ((n) << 6) /**< @brief 1st channel in seq. */
+#define ADC_SQR1_SQ2_N(n) ((n) << 12) /**< @brief 2nd channel in seq. */
+#define ADC_SQR1_SQ3_N(n) ((n) << 18) /**< @brief 3rd channel in seq. */
+#define ADC_SQR1_SQ4_N(n) ((n) << 24) /**< @brief 4th channel in seq. */
+
+#define ADC_SQR2_SQ5_N(n) ((n) << 0) /**< @brief 5th channel in seq. */
+#define ADC_SQR2_SQ6_N(n) ((n) << 6) /**< @brief 6th channel in seq. */
+#define ADC_SQR2_SQ7_N(n) ((n) << 12) /**< @brief 7th channel in seq. */
+#define ADC_SQR2_SQ8_N(n) ((n) << 18) /**< @brief 8th channel in seq. */
+#define ADC_SQR2_SQ9_N(n) ((n) << 24) /**< @brief 9th channel in seq. */
+
+#define ADC_SQR3_SQ10_N(n) ((n) << 0) /**< @brief 10th channel in seq.*/
+#define ADC_SQR3_SQ11_N(n) ((n) << 6) /**< @brief 11th channel in seq.*/
+#define ADC_SQR3_SQ12_N(n) ((n) << 12) /**< @brief 12th channel in seq.*/
+#define ADC_SQR3_SQ13_N(n) ((n) << 18) /**< @brief 13th channel in seq.*/
+#define ADC_SQR3_SQ14_N(n) ((n) << 24) /**< @brief 14th channel in seq.*/
+
+#define ADC_SQR4_SQ15_N(n) ((n) << 0) /**< @brief 15th channel in seq.*/
+#define ADC_SQR4_SQ16_N(n) ((n) << 6) /**< @brief 16th channel in seq.*/
+/** @} */
+
+/**
+ * @name Sampling rate settings helper macros
+ * @{
+ */
+#define ADC_SMPR1_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */
+#define ADC_SMPR1_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */
+#define ADC_SMPR1_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */
+#define ADC_SMPR1_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */
+#define ADC_SMPR1_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */
+#define ADC_SMPR1_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */
+#define ADC_SMPR1_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */
+#define ADC_SMPR1_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */
+#define ADC_SMPR1_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */
+#define ADC_SMPR1_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */
+
+#define ADC_SMPR2_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */
+#define ADC_SMPR2_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */
+#define ADC_SMPR2_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */
+#define ADC_SMPR2_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */
+#define ADC_SMPR2_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */
+#define ADC_SMPR2_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */
+#define ADC_SMPR2_SMP_AN16(n) ((n) << 18) /**< @brief AN16 sampling time. */
+#define ADC_SMPR2_SMP_AN17(n) ((n) << 21) /**< @brief AN17 sampling time. */
+#define ADC_SMPR2_SMP_AN18(n) ((n) << 24) /**< @brief AN18 sampling time. */
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD1;
+#endif
+
+#if STM32_ADC_USE_ADC2 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD2;
+#endif
+
+#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD3;
+#endif
+
+#if STM32_ADC_USE_ADC4 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD4;
+#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 adcSTM32EnableVREF(ADCDriver *adcp);
+ void adcSTM32DisableVREF(ADCDriver *adcp);
+ void adcSTM32EnableTS(ADCDriver *adcp);
+ void adcSTM32DisableTS(ADCDriver *adcp);
+ void adcSTM32EnableVBAT(ADCDriver *adcp);
+ void adcSTM32DisableVBAT(ADCDriver *adcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ADC */
+
+#endif /* HAL_ADC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt new file mode 100644 index 0000000..fbfe6c2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv3/notes.txt @@ -0,0 +1,22 @@ +STM32 ADCv3 driver.
+
+Driver capability:
+
+- Supports the STM32 "fast" ADC found on F3, L4, L4+ and G4 sub-families.
+
+The file registry must export:
+
+STM32_HAS_ADCx - ADCx presence flag (1..4).
+STM32_ADC1_HANDLER - IRQ vector name for ADC1.
+STM32_ADC1_NUMBER - IRQ vector number for ADC1.
+STM32_ADC2_HANDLER - IRQ vector name for ADC2.
+STM32_ADC2_NUMBER - IRQ vector number for ADC2.
+STM32_ADC3_HANDLER - IRQ vector name for ADC3.
+STM32_ADC3_NUMBER - IRQ vector number for ADC3.
+STM32_ADC4_HANDLER - IRQ vector name for ADC4.
+STM32_ADC4_NUMBER - IRQ vector number for ADC4.
+
+If there is no DMAMUX then the file registry must export also:
+
+STM32_ADCx_DMA_MSK - Mask of the compatible DMA channels (1..4).
+STM32_ADCx_DMA_CHN - Mask of the channels mapping (1..4).
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk new file mode 100644 index 0000000..91bc885 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c new file mode 100644 index 0000000..2b85dbd --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c @@ -0,0 +1,822 @@ +/*
+ 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 ADCv4/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. */
+/*===========================================================================*/
+
+#if STM32_ADC_DUAL_MODE == TRUE
+#if STM32_ADC_COMPACT_SAMPLES == TRUE
+/* Compact type dual mode, 2x8-bit.*/
+#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD)
+#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_BYTE | STM32_BDMA_CR_PSIZE_BYTE)
+#define ADC_DMA_DAMDF ADC_CCR_DAMDF_BYTE
+
+#else /* STM32_ADC_COMPACT_SAMPLES == FALSE */
+/* Large type dual mode, 2x16bit.*/
+#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD)
+#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_HWORD | STM32_BDMA_CR_PSIZE_HWORD)
+#define ADC_DMA_DAMDF ADC_CCR_DAMDF_HWORD
+#endif /* !STM32_ADC_COMPACT_SAMPLES */
+
+#else /* STM32_ADC_DUAL_MODE == FALSE */
+#if STM32_ADC_COMPACT_SAMPLES
+/* Compact type single mode, 8-bit.*/
+#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_PSIZE_BYTE)
+#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_BYTE | STM32_BDMA_CR_PSIZE_BYTE)
+#define ADC_DMA_DAMDF ADC_CCR_DAMDF_DISABLED
+
+#else /* STM32_ADC_COMPACT_SAMPLES == FALSE */
+/* Large type single mode, 16-bit.*/
+#define ADC12_DMA_SIZE (STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD)
+#define ADC3_BDMA_SIZE (STM32_BDMA_CR_MSIZE_HWORD | STM32_BDMA_CR_PSIZE_HWORD)
+#define ADC_DMA_DAMDF ADC_CCR_DAMDF_DISABLED
+#endif /* STM32_ADC_COMPACT_SAMPLES == FALSE */
+#endif /* STM32_ADC_DUAL_MODE == FALSE */
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief ADC1 driver identifier.*/
+#if STM32_ADC_USE_ADC12 || defined(__DOXYGEN__)
+ADCDriver ADCD1;
+#endif
+
+/** @brief ADC3 driver identifier.*/
+#if STM32_ADC_USE_ADC3 || defined(__DOXYGEN__)
+ADCDriver ADCD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const ADCConfig default_config = {
+ .difsel = 0U
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the ADC voltage regulator.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_vreg_on(ADCDriver *adcp) {
+
+ adcp->adcm->CR = ADC_CR_ADVREGEN;
+#if STM32_ADC_DUAL_MODE
+ if (&ADCD1 == adcp) {
+ adcp->adcs->CR = ADC_CR_ADVREGEN;
+ }
+#endif
+ osalSysPolledDelayX(OSAL_US2RTC(STM32_SYS_CK, 10U));
+}
+
+/**
+ * @brief Disables the ADC voltage regulator.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_vreg_off(ADCDriver *adcp) {
+
+ adcp->adcm->CR = ADC_CR_DEEPPWD;
+#if STM32_ADC_DUAL_MODE
+ if (&ADCD1 == adcp) {
+ adcp->adcs->CR = ADC_CR_DEEPPWD;
+ }
+#endif
+}
+
+/**
+ * @brief Enables the ADC analog circuit.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_analog_on(ADCDriver *adcp) {
+
+ adcp->adcm->ISR = ADC_ISR_ADRDY;
+ adcp->adcm->CR |= ADC_CR_ADEN;
+ while ((adcp->adcm->ISR & ADC_ISR_ADRDY) == 0U)
+ ;
+#if STM32_ADC_DUAL_MODE
+ if (&ADCD1 == adcp) {
+ adcp->adcs->ISR = ADC_ISR_ADRDY;
+ adcp->adcs->CR |= ADC_CR_ADEN;
+ while ((adcp->adcs->ISR & ADC_ISR_ADRDY) == 0U)
+ ;
+ }
+#endif
+}
+
+/**
+ * @brief Disables the ADC analog circuit.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_analog_off(ADCDriver *adcp) {
+
+ adcp->adcm->CR |= ADC_CR_ADDIS;
+ while ((adcp->adcm->CR & ADC_CR_ADDIS) != 0U)
+ ;
+#if STM32_ADC_DUAL_MODE
+ if (&ADCD1 == adcp) {
+ adcp->adcs->CR |= ADC_CR_ADDIS;
+ while ((adcp->adcs->CR & ADC_CR_ADDIS) != 0U)
+ ;
+ }
+#endif
+}
+
+/**
+ * @brief Calibrates and ADC unit.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_calibrate(ADCDriver *adcp) {
+
+ osalDbgAssert(adcp->adcm->CR == ADC_CR_ADVREGEN, "invalid register state");
+
+ adcp->adcm->CR &= ~(ADC_CR_ADCALDIF | ADC_CR_ADCALLIN);
+ adcp->adcm->CR |= adcp->config->calibration & (ADC_CR_ADCALDIF |
+ ADC_CR_ADCALLIN);
+ adcp->adcm->CR |= ADC_CR_ADCAL;
+ while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0U)
+ ;
+#if STM32_ADC_DUAL_MODE
+ if (&ADCD1 == adcp) {
+ osalDbgAssert(adcp->adcs->CR == ADC_CR_ADVREGEN, "invalid register state");
+
+ adcp->adcs->CR &= ~(ADC_CR_ADCALDIF | ADC_CR_ADCALLIN);
+ adcp->adcs->CR |= adcp->config->calibration & (ADC_CR_ADCALDIF |
+ ADC_CR_ADCALLIN);
+ adcp->adcs->CR |= ADC_CR_ADCAL;
+ while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0U)
+ ;
+ }
+#endif
+}
+
+/**
+ * @brief Stops an ongoing conversion, if any.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ */
+static void adc_lld_stop_adc(ADCDriver *adcp) {
+
+ if (adcp->adcm->CR & ADC_CR_ADSTART) {
+ adcp->adcm->CR |= ADC_CR_ADSTP;
+ while (adcp->adcm->CR & ADC_CR_ADSTP)
+ ;
+ }
+#if !defined(STM32H723xx) || STM32_ADC_USE_ADC3 == FALSE
+ adcp->adcm->PCSEL = 0U;
+#endif
+}
+
+#if (STM32_ADC_USE_ADC12 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @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_dma_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);
+ }
+ }
+ }
+}
+#endif /* STM32_ADC_USE_ADC12 == TRUE */
+
+#if (STM32_ADC_USE_ADC3 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief ADC BDMA 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);
+ }
+ }
+ }
+}
+#endif /* STM32_ADC_USE_ADC3 == TRUE */
+
+/**
+ * @brief ADC IRQ service routine.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] isr content of the ISR register
+ */
+static void adc_lld_serve_interrupt(ADCDriver *adcp, uint32_t 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 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);
+ }
+ if (isr & ADC_ISR_AWD1) {
+ /* Analog watchdog error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD1);
+ }
+ if (isr & ADC_ISR_AWD2) {
+ /* Analog watchdog error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD2);
+ }
+ if (isr & ADC_ISR_AWD3) {
+ /* Analog watchdog error.*/
+ _adc_isr_error_code(adcp, ADC_ERR_AWD3);
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if (STM32_ADC_USE_ADC12 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief ADC1/ADC2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC12_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ isr = ADC1->ISR;
+#if STM32_ADC_DUAL_MODE
+ isr |= ADC2->ISR;
+#endif
+ ADC1->ISR = isr;
+#if STM32_ADC_DUAL_MODE
+ ADC2->ISR = isr;
+#endif
+#if defined(STM32_ADC_ADC12_IRQ_HOOK)
+ STM32_ADC_ADC12_IRQ_HOOK
+#endif
+ adc_lld_serve_interrupt(&ADCD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_ADC_USE_ADC12 == TRUE */
+
+#if (STM32_ADC_USE_ADC3 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief ADC3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_ADC3_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ isr = ADC3->ISR;
+ ADC3->ISR = isr;
+#if defined(STM32_ADC_ADC3_IRQ_HOOK)
+ STM32_ADC_ADC3_IRQ_HOOK
+#endif
+ adc_lld_serve_interrupt(&ADCD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_ADC_USE_ADC3 == TRUE */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ADC driver initialization.
+ *
+ * @notapi
+ */
+void adc_lld_init(void) {
+
+#if STM32_ADC_USE_ADC12 == TRUE
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD1);
+ ADCD1.adcc = ADC12_COMMON;
+ ADCD1.adcm = ADC1;
+#if STM32_ADC_DUAL_MODE
+ ADCD1.adcs = ADC2;
+#endif
+ ADCD1.data.dma = NULL;
+ ADCD1.dmamode = ADC12_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 */
+
+#if STM32_ADC_USE_ADC3 == TRUE
+ /* Driver initialization.*/
+ adcObjectInit(&ADCD3);
+ ADCD3.adcc = ADC3_COMMON;
+ ADCD3.adcm = ADC3;
+ ADCD3.data.bdma = NULL;
+ ADCD3.dmamode = ADC3_BDMA_SIZE |
+ STM32_BDMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) |
+ STM32_BDMA_CR_DIR_P2M |
+ STM32_BDMA_CR_MINC | STM32_BDMA_CR_TCIE |
+ STM32_BDMA_CR_TEIE;
+ nvicEnableVector(STM32_ADC3_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY);
+#endif /* STM32_ADC_USE_ADC3 == TRUE */
+
+ /* ADC units pre-initializations.*/
+#if (STM32_HAS_ADC1 == TRUE) && (STM32_HAS_ADC2 == TRUE)
+#if STM32_ADC_USE_ADC12 == TRUE
+ rccEnableADC12(true);
+ rccResetADC12();
+ ADC12_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_DAMDF;
+ rccDisableADC12();
+#endif
+#if STM32_ADC_USE_ADC3 == TRUE
+ rccEnableADC3(true);
+ rccResetADC3();
+ ADC3_COMMON->CCR = STM32_ADC_ADC3_CLOCK_MODE | STM32_ADC_ADC3_PRESC;
+ rccDisableADC3();
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the ADC peripheral.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @notapi
+ */
+void adc_lld_start(ADCDriver *adcp) {
+
+ /* Handling the default configuration.*/
+ if (adcp->config == NULL) {
+ adcp->config = &default_config;
+ }
+
+ /* If in stopped state then enables the ADC and DMA clocks.*/
+ if (adcp->state == ADC_STOP) {
+#if STM32_ADC_USE_ADC12 == TRUE
+ if (&ADCD1 == adcp) {
+ adcp->data.dma = dmaStreamAllocI(STM32_ADC_ADC12_DMA_STREAM,
+ STM32_ADC_ADC12_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_dma_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->data.dma != NULL, "unable to allocate stream");
+ rccEnableADC12(true);
+ dmaSetRequestSource(adcp->data.dma, STM32_DMAMUX1_ADC1);
+
+ /* Setting DMA peripheral-side pointer.*/
+#if STM32_ADC_DUAL_MODE
+ dmaStreamSetPeripheral(adcp->data.dma, &adcp->adcc->CDR);
+#else
+ dmaStreamSetPeripheral(adcp->data.dma, &adcp->adcm->DR);
+#endif
+
+ /* Differential channels setting.*/
+#if STM32_ADC_DUAL_MODE
+ adcp->adcm->DIFSEL = adcp->config->difsel;
+ adcp->adcs->DIFSEL = adcp->config->difsel;
+#else
+ adcp->adcm->DIFSEL = adcp->config->difsel;
+#endif
+ }
+#endif /* STM32_ADC_USE_ADC12 == TRUE */
+
+#if STM32_ADC_USE_ADC3 == TRUE
+ if (&ADCD3 == adcp) {
+ adcp->data.bdma = bdmaStreamAllocI(STM32_ADC_ADC3_BDMA_STREAM,
+ STM32_ADC_ADC3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)adc_lld_serve_bdma_interrupt,
+ (void *)adcp);
+ osalDbgAssert(adcp->data.bdma != NULL, "unable to allocate stream");
+ rccEnableADC3(true);
+ bdmaSetRequestSource(adcp->data.bdma, STM32_DMAMUX2_ADC3_REQ);
+
+ /* Setting DMA peripheral-side pointer.*/
+ bdmaStreamSetPeripheral(adcp->data.bdma, &adcp->adcm->DR);
+
+ /* Differential channels setting.*/
+ adcp->adcm->DIFSEL = adcp->config->difsel;
+ }
+#endif /* STM32_ADC_USE_ADC3 == TRUE */
+
+ /* Master ADC calibration.*/
+ adc_lld_vreg_on(adcp);
+ adc_lld_calibrate(adcp);
+
+ /* Configure the ADC boost. */
+#if STM32_ADC_USE_ADC12 == TRUE
+ if (&ADCD1 == adcp) {
+ adcp->adcm->CR |= STM32_ADC12_BOOST;
+#if STM32_ADC_DUAL_MODE
+ adcp->adcs->CR |= STM32_ADC12_BOOST;
+#endif
+ }
+#endif
+
+#if STM32_ADC_USE_ADC3 == TRUE
+ if (&ADCD3 == adcp) {
+ adcp->adcm->CR |= STM32_ADC3_BOOST;
+ }
+#endif
+
+ /* Master ADC enabled here in order to reduce conversions latencies.*/
+ adc_lld_analog_on(adcp);
+ }
+}
+
+/**
+ * @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) {
+
+ /* Stopping the ongoing conversion, if any.*/
+ adc_lld_stop_adc(adcp);
+
+ /* Disabling ADC analog circuit and regulator.*/
+ adc_lld_analog_off(adcp);
+ adc_lld_vreg_off(adcp);
+
+#if STM32_ADC_USE_ADC12 == TRUE
+ if (&ADCD1 == adcp) {
+
+ /* Releasing the associated DMA channel.*/
+ dmaStreamFreeI(adcp->data.dma);
+ adcp->data.dma = NULL;
+
+ /* Resetting CCR options except default ones.*/
+ adcp->adcc->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_DAMDF;
+ rccDisableADC12();
+ }
+#endif
+
+#if STM32_ADC_USE_ADC3 == TRUE
+ if (&ADCD3 == adcp) {
+
+ /* Releasing the associated BDMA channel.*/
+ bdmaStreamFreeI(adcp->data.bdma);
+ adcp->data.bdma = NULL;
+
+ /* Resetting CCR options except default ones.*/
+ adcp->adcc->CCR = STM32_ADC_ADC3_CLOCK_MODE | STM32_ADC_ADC3_PRESC;
+ rccDisableADC3();
+ }
+#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 dmamode, cfgr;
+ const ADCConversionGroup *grpp = adcp->grpp;
+
+#if STM32_ADC_USE_ADC12 == TRUE
+#if STM32_ADC_DUAL_MODE
+ uint32_t ccr;
+#endif
+ if (&ADCD1 == adcp) {
+#if STM32_ADC_DUAL_MODE
+ ccr = grpp->ccr & ~(ADC_CCR_CKMODE_MASK | ADC_CCR_DAMDF_MASK);
+ osalDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0),
+ "odd number of channels in dual mode");
+#endif
+
+ /* Calculating control registers values.*/
+ dmamode = adcp->dmamode;
+ if (grpp->circular) {
+ dmamode |= STM32_DMA_CR_CIRC;
+ cfgr = grpp->cfgr | ADC_CFGR_DMNGT_CIRCULAR;
+ if (adcp->depth > 1) {
+ /* If circular buffer depth > 1, then the half transfer interrupt
+ is enabled in order to allow streaming processing.*/
+ dmamode |= STM32_DMA_CR_HTIE;
+ }
+ }
+ else {
+ cfgr = grpp->cfgr | ADC_CFGR_DMNGT_ONESHOT;
+ }
+
+ /* DMA setup.*/
+ dmaStreamSetMemory0(adcp->data.dma, adcp->samples);
+#if STM32_ADC_DUAL_MODE
+ dmaStreamSetTransactionSize(adcp->data.dma, ((uint32_t)grpp->num_channels / 2U) *
+ (uint32_t)adcp->depth);
+#else
+ dmaStreamSetTransactionSize(adcp->data.dma, (uint32_t)grpp->num_channels *
+ (uint32_t)adcp->depth);
+#endif
+ dmaStreamSetMode(adcp->data.dma, dmamode);
+ dmaStreamEnable(adcp->data.dma);
+ }
+#endif /* STM32_ADC_USE_ADC12 == TRUE */
+
+#if STM32_ADC_USE_ADC3 == TRUE
+ if (&ADCD3 == adcp) {
+ /* Calculating control registers values.*/
+ dmamode = adcp->dmamode;
+ if (grpp->circular) {
+ dmamode |= STM32_BDMA_CR_CIRC;
+ cfgr = grpp->cfgr | ADC_CFGR_DMNGT_CIRCULAR;
+ if (adcp->depth > 1) {
+ /* If circular buffer depth > 1, then the half transfer interrupt
+ is enabled in order to allow streaming processing.*/
+ dmamode |= STM32_BDMA_CR_HTIE;
+ }
+ }
+ else {
+ cfgr = grpp->cfgr | ADC_CFGR_DMNGT_ONESHOT;
+ }
+
+ /* DMA setup.*/
+ bdmaStreamSetMemory(adcp->data.bdma, adcp->samples);
+ bdmaStreamSetTransactionSize(adcp->data.bdma, (uint32_t)grpp->num_channels *
+ (uint32_t)adcp->depth);
+ bdmaStreamSetMode(adcp->data.bdma, dmamode);
+ bdmaStreamEnable(adcp->data.bdma);
+ }
+#endif /* STM32_ADC_USE_ADC3 == TRUE */
+
+ /* ADC setup, if it is defined a callback for the analog watch dog then it
+ is enabled.*/
+ adcp->adcm->ISR = adcp->adcm->ISR;
+ adcp->adcm->IER = ADC_IER_OVRIE | ADC_IER_AWD1IE;
+#if STM32_ADC_DUAL_MODE == TRUE && STM32_ADC_USE_ADC12 == TRUE
+ /* Configuration for dual mode ADC12 */
+ if (&ADCD1 == adcp) {
+ /* Configuring the CCR register with the user-specified settings
+ in the conversion group configuration structure, static settings are
+ preserved.*/
+ adcp->adcc->CCR = (adcp->adcc->CCR &
+ (ADC_CCR_CKMODE_MASK | ADC_CCR_DAMDF_MASK)) | ccr;
+
+ adcp->adcm->CFGR2 = grpp->cfgr2;
+ adcp->adcm->PCSEL = grpp->pcsel;
+ adcp->adcm->LTR1 = grpp->ltr1;
+ adcp->adcm->HTR1 = grpp->htr1;
+ adcp->adcm->LTR2 = grpp->ltr2;
+ adcp->adcm->HTR2 = grpp->htr2;
+ adcp->adcm->LTR3 = grpp->ltr3;
+ adcp->adcm->HTR3 = grpp->htr3;
+ adcp->adcm->SMPR1 = grpp->smpr[0];
+ adcp->adcm->SMPR2 = grpp->smpr[1];
+ adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
+ adcp->adcm->SQR2 = grpp->sqr[1];
+ adcp->adcm->SQR3 = grpp->sqr[2];
+ adcp->adcm->SQR4 = grpp->sqr[3];
+ adcp->adcs->CFGR2 = grpp->cfgr2;
+ adcp->adcs->PCSEL = grpp->pcsel;
+ adcp->adcs->LTR1 = grpp->ltr1;
+ adcp->adcs->HTR1 = grpp->htr1;
+ adcp->adcs->LTR2 = grpp->ltr2;
+ adcp->adcs->HTR2 = grpp->htr2;
+ adcp->adcs->LTR3 = grpp->ltr3;
+ adcp->adcs->HTR3 = grpp->htr3;
+ adcp->adcs->SMPR1 = grpp->ssmpr[0];
+ adcp->adcs->SMPR2 = grpp->ssmpr[1];
+ adcp->adcs->SQR1 = grpp->ssqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
+ adcp->adcs->SQR2 = grpp->ssqr[1];
+ adcp->adcs->SQR3 = grpp->ssqr[2];
+ adcp->adcs->SQR4 = grpp->ssqr[3];
+
+ /* ADC configuration.*/
+ adcp->adcm->CFGR = cfgr;
+ adcp->adcs->CFGR = cfgr;
+ }
+
+#endif /* STM32_ADC_DUAL_MODE == TRUE && STM32_ADC_USE_ADC12 == TRUE */
+
+#if STM32_ADC_DUAL_MODE == FALSE || STM32_ADC_USE_ADC3 == TRUE
+ /* Configuration for ADC3 and single mode ADC1 */
+#if STM32_ADC_DUAL_MODE == TRUE && STM32_ADC_USE_ADC3 == TRUE
+ if (&ADCD3 == adcp)
+#endif
+ {
+ adcp->adcm->CFGR2 = grpp->cfgr2;
+#if !defined(STM32H723xx) || STM32_ADC_USE_ADC3 == FALSE
+ adcp->adcm->PCSEL = grpp->pcsel;
+#endif
+ adcp->adcm->LTR1 = grpp->ltr1;
+ adcp->adcm->HTR1 = grpp->htr1;
+ adcp->adcm->LTR2 = grpp->ltr2;
+ adcp->adcm->HTR2 = grpp->htr2;
+ adcp->adcm->LTR3 = grpp->ltr3;
+ adcp->adcm->HTR3 = grpp->htr3;
+ adcp->adcm->SMPR1 = grpp->smpr[0];
+ adcp->adcm->SMPR2 = grpp->smpr[1];
+ adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels);
+ adcp->adcm->SQR2 = grpp->sqr[1];
+ adcp->adcm->SQR3 = grpp->sqr[2];
+ adcp->adcm->SQR4 = grpp->sqr[3];
+
+ /* ADC configuration.*/
+ adcp->adcm->CFGR = cfgr;
+ }
+#endif
+
+ /* Starting conversion.*/
+ adcp->adcm->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) {
+
+#if STM32_ADC_USE_ADC12 == TRUE
+ if (&ADCD1 == adcp) {
+ dmaStreamDisable(adcp->data.dma);
+ }
+#endif /* STM32_ADC_USE_ADC12 == TRUE */
+
+#if STM32_ADC_USE_ADC3 == TRUE
+ if (&ADCD3 == adcp) {
+ bdmaStreamDisable(adcp->data.bdma);
+ }
+#endif /* STM32_ADC_USE_ADC12 == TRUE */
+
+ adc_lld_stop_adc(adcp);
+}
+
+/**
+ * @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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->CCR &= ~ADC_CCR_TSEN;
+}
+
+/**
+ * @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) {
+
+ adcp->adcc->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) {
+
+ adcp->adcc->CCR &= ~ADC_CCR_VBATEN;
+}
+
+#endif /* HAL_USE_ADC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h new file mode 100644 index 0000000..5f3cf46 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h @@ -0,0 +1,737 @@ +/*
+ 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 ADCv4/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 Available analog channels
+ * @{
+ */
+#define ADC_CHANNEL_IN0 0U /**< @brief External analog input 0. */
+#define ADC_CHANNEL_IN1 1U /**< @brief External analog input 1. */
+#define ADC_CHANNEL_IN2 2U /**< @brief External analog input 2. */
+#define ADC_CHANNEL_IN3 3U /**< @brief External analog input 3. */
+#define ADC_CHANNEL_IN4 4U /**< @brief External analog input 4. */
+#define ADC_CHANNEL_IN5 5U /**< @brief External analog input 5. */
+#define ADC_CHANNEL_IN6 6U /**< @brief External analog input 6. */
+#define ADC_CHANNEL_IN7 7U /**< @brief External analog input 7. */
+#define ADC_CHANNEL_IN8 8U /**< @brief External analog input 8. */
+#define ADC_CHANNEL_IN9 9U /**< @brief External analog input 9. */
+#define ADC_CHANNEL_IN10 10U /**< @brief External analog input 10. */
+#define ADC_CHANNEL_IN11 11U /**< @brief External analog input 11. */
+#define ADC_CHANNEL_IN12 12U /**< @brief External analog input 12. */
+#define ADC_CHANNEL_IN13 13U /**< @brief External analog input 13. */
+#define ADC_CHANNEL_IN14 14U /**< @brief External analog input 14. */
+#define ADC_CHANNEL_IN15 15U /**< @brief External analog input 15. */
+#define ADC_CHANNEL_IN16 16U /**< @brief External analog input 16. */
+#define ADC_CHANNEL_IN17 17U /**< @brief External analog input 17. */
+#define ADC_CHANNEL_IN18 18U /**< @brief External analog input 18. */
+#define ADC_CHANNEL_IN19 19U /**< @brief External analog input 19. */
+/** @} */
+
+/**
+ * @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)
+#define ADC_SELMASK_IN19 (1U << ADC_CHANNEL_IN19)
+/** @} */
+
+/**
+ * @name Sampling rates
+ * @{
+ */
+#if defined(STM32H7XX)
+#if !defined(STM32H723xx) || STM32_ADC_USE_ADC3 == FALSE
+#define ADC_SMPR_SMP_1P5 0U /**< @brief 9 cycles conversion time */
+#define ADC_SMPR_SMP_2P5 1U /**< @brief 10 cycles conversion time. */
+#define ADC_SMPR_SMP_8P5 2U /**< @brief 16 cycles conversion time. */
+#define ADC_SMPR_SMP_16P5 3U /**< @brief 24 cycles conversion time. */
+#define ADC_SMPR_SMP_32P5 4U /**< @brief 40 cycles conversion time. */
+#define ADC_SMPR_SMP_64P5 5U /**< @brief 72 cycles conversion time. */
+#define ADC_SMPR_SMP_384P5 6U /**< @brief 392 cycles conversion time. */
+#define ADC_SMPR_SMP_810P5 7U /**< @brief 818 cycles conversion time. */
+#else
+#define ADC_SMPR_SMP_2P5 0U /**< @brief cycles conversion time */
+#define ADC_SMPR_SMP_6P5 1U /**< @brief cycles conversion time. */
+#define ADC_SMPR_SMP_12P5 2U /**< @brief cycles conversion time. */
+#define ADC_SMPR_SMP_24P5 3U /**< @brief cycles conversion time. */
+#define ADC_SMPR_SMP_47P5 4U /**< @brief cycles conversion time. */
+#define ADC_SMPR_SMP_92P5 5U /**< @brief cycles conversion time. */
+#define ADC_SMPR_SMP_247P5 6U /**< @brief cycles conversion time. */
+#define ADC_SMPR_SMP_640P5 7U /**< @brief cycles conversion time. */
+#endif
+#endif
+/** @} */
+
+/**
+ * @name CFGR register configuration helpers
+ * @{
+ */
+#define ADC_CFGR_DMNGT_MASK (3U << 0U)
+#define ADC_CFGR_DMNGT_NODMA (0U << 0U)
+#define ADC_CFGR_DMNGT_ONESHOT (1U << 0U)
+#define ADC_CFGR_DMNGT_DFSDM (2U << 0U)
+#define ADC_CFGR_DMNGT_CIRCULAR (3U << 0U)
+
+#define ADC_CFGR_RES_MASK (7U << 2U)
+#define ADC_CFGR_RES_16BITS (0U << 2U)
+#define ADC_CFGR_RES_10BITS (3U << 2U)
+#if !defined(STM32_ENFORCE_H7_REV_XY)
+#define ADC_CFGR_RES_14BITS (5U << 2U)
+#define ADC_CFGR_RES_12BITS (6U << 2U)
+#define ADC_CFGR_RES_8BITS (7U << 2U)
+#else
+#define ADC_CFGR_RES_14BITS (1U << 2U)
+#define ADC_CFGR_RES_12BITS (2U << 2U)
+#define ADC_CFGR_RES_8BITS (4U << 2U)
+#endif
+
+#define ADC_CFGR_EXTSEL_MASK (15U << 5U)
+#define ADC_CFGR_EXTSEL_SRC(n) ((n) << 5U)
+
+#define ADC_CFGR_EXTEN_MASK (3U << 10U)
+#define ADC_CFGR_EXTEN_DISABLED (0U << 10U)
+#define ADC_CFGR_EXTEN_RISING (1U << 10U)
+#define ADC_CFGR_EXTEN_FALLING (2U << 10U)
+#define ADC_CFGR_EXTEN_BOTH (3U << 10U)
+
+#define ADC_CFGR_DISCEN_MASK (1U << 16U)
+#define ADC_CFGR_DISCEN_DISABLED (0U << 16U)
+#define ADC_CFGR_DISCEN_ENABLED (1U << 16U)
+
+#define ADC_CFGR_DISCNUM_MASK (7U << 17U)
+#define ADC_CFGR_DISCNUM_VAL(n) ((n) << 17U)
+/** @} */
+
+/**
+ * @name CCR register configuration helpers
+ * @{
+ */
+#define ADC_CCR_DUAL_MASK (31U << 0U)
+#define ADC_CCR_DUAL_FIELD(n) ((n) << 0U)
+#define ADC_CCR_DUAL_INDEPENDENT (0U << 0U) /**< @brief Independent, dual mode disabled. */
+#define ADC_CCR_DUAL_REG_SIMULT (6U << 0U) /**< @brief Regular simultaneous. */
+#define ADC_CCR_DUAL_REG_INTERL (7U << 0U) /**< @brief Regular interleaved. */
+#define ADC_CCR_DUAL_INJ_SIMULT (5U << 0U) /**< @brief Injected simultaneous. */
+#define ADC_CCR_DUAL_INJ_ALTERNATE (9U << 0U) /**< @brief Injected alternate trigger. */
+#define ADC_CCR_DUAL_REG_SIM_INJ_SIM (1U << 0U) /**< @brief Combined regular simultaneous + injected simultaneous. */
+#define ADC_CCR_DUAL_REG_SIM_INJ_ALT (2U << 0U) /**< @brief Combined regular simultaneous + injected alternate trigger. */
+#define ADC_CCR_DUAL_REG_INT_INJ_SIM (3U << 0U) /**< @brief Combined regular interleaved + injected simultaneous. */
+#define ADC_CCR_DELAY_MASK (15U << 8U)
+#define ADC_CCR_DELAY_FIELD(n) ((n) << 8U)
+#define ADC_CCR_DAMDF_MASK (3U << 14U)
+#define ADC_CCR_DAMDF_DISABLED (0U << 14U)
+#define ADC_CCR_DAMDF_HWORD (2U << 14U)
+#define ADC_CCR_DAMDF_BYTE (3U << 14U)
+#define ADC_CCR_CKMODE_MASK (3U << 16U)
+#define ADC_CCR_CKMODE_ADCCK (0U << 16U)
+#define ADC_CCR_CKMODE_AHB_DIV1 (1U << 16U)
+#define ADC_CCR_CKMODE_AHB_DIV2 (2U << 16U)
+#define ADC_CCR_CKMODE_AHB_DIV4 (3U << 16U)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Enables the ADC1 and ADC2 master/slave mode.
+ */
+#if !defined(STM32_ADC_DUAL_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_DUAL_MODE FALSE
+#endif
+
+/**
+ * @brief Makes the ADC samples type an 8bits one.
+ * @note 10, 12, 14 and 16 bits sampling mode must not be used when this
+ * option is enabled.
+ */
+#if !defined(STM32_ADC_COMPACT_SAMPLES) || defined(__DOXYGEN__)
+#define STM32_ADC_COMPACT_SAMPLES 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 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 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_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 5
+#endif
+
+/**
+ * @brief ADC3 interrupt priority level setting.
+ */
+#if !defined(STM32_ADC_ADC3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_IRQ_PRIORITY 5
+#endif
+
+/**
+ * @brief ADC1/ADC2 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC12_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4
+#endif
+
+/**
+ * @brief ADC3 clock source and mode.
+ */
+#if !defined(STM32_ADC_ADC3_CLOCK_MODE) || defined(__DOXYGEN__)
+#define STM32_ADC_ADC3_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Supported devices checks.*/
+#if !defined(STM32H7XX)
+#error "ADCv4 only supports H7 STM32 devices"
+#endif
+
+/* Registry checks.*/
+#if !defined(STM32_HAS_ADC1) || !defined(STM32_HAS_ADC2) || \
+ !defined(STM32_HAS_ADC3)
+#error "STM32_HAS_ADCx not defined in registry"
+#endif
+
+/* Units checks.*/
+#if STM32_ADC_USE_ADC12 && !STM32_HAS_ADC1
+#error "ADC1 not present in the selected device"
+#endif
+
+#if STM32_ADC_DUAL_MODE && !STM32_HAS_ADC2
+#error "ADC2 not present in the selected device"
+#endif
+
+#if STM32_ADC_USE_ADC3 && !STM32_HAS_ADC3
+#error "ADC3 not present in the selected device"
+#endif
+
+/* IRQ handlers checks.*/
+#if STM32_HAS_ADC1 && !defined(STM32_ADC12_HANDLER)
+#error "STM32_ADC12_HANDLER not defined in registry"
+#endif
+
+#if STM32_HAS_ADC2 && !defined(STM32_ADC12_HANDLER)
+#error "STM32_ADC12_HANDLER not defined in registry"
+#endif
+
+#if STM32_HAS_ADC3 && !defined(STM32_ADC3_HANDLER)
+#error "STM32_ADC3_HANDLER not defined in registry"
+#endif
+
+/* IRQ vector numbers checks.*/
+#if STM32_HAS_ADC1 && !defined(STM32_ADC12_NUMBER)
+#error "STM32_ADC12_NUMBER not defined in registry"
+#endif
+
+#if STM32_HAS_ADC2 && !defined(STM32_ADC12_NUMBER)
+#error "STM32_ADC12_NUMBER not defined in registry"
+#endif
+
+#if STM32_HAS_ADC3 && !defined(STM32_ADC3_NUMBER)
+#error "STM32_ADC3_NUMBER not defined in registry"
+#endif
+
+/* At least one ADC must be assigned.*/
+#if !STM32_ADC_USE_ADC12 && !STM32_ADC_USE_ADC3
+#error "ADC driver activated but no ADC peripheral assigned"
+#endif
+
+/* Dual mode is only supported with ADC12.*/
+#if !STM32_ADC_USE_ADC12 && STM32_ADC_DUAL_MODE
+#error "STM32_ADC_DUAL_MODE only supported with ADC12"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_ADC_USE_ADC12 && !defined(STM32_ADC_ADC12_DMA_STREAM)
+#error "STM32_ADC_ADC12_DMA_STREAM not defined"
+#endif
+
+#if STM32_ADC_USE_ADC3 && !defined(STM32_ADC_ADC3_BDMA_STREAM)
+#error "STM32_ADC_ADC3_BDMA_STREAM not defined"
+#endif
+
+/* DMA channel range tests.*/
+#if STM32_ADC_USE_ADC12 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_ADC_ADC12_DMA_STREAM)
+#error "Invalid DMA channel assigned to ADC12"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !STM32_BDMA_IS_VALID_STREAM(STM32_ADC_ADC3_BDMA_STREAM)
+#error "Invalid DMA channel assigned to ADC3"
+#endif
+
+/* DMA priority tests.*/
+#if STM32_ADC_USE_ADC12 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC12_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to ADC1"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to ADC3"
+#endif
+
+/* ADC IRQ priority tests.*/
+#if STM32_ADC_USE_ADC12 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC1"
+#endif
+
+#if STM32_ADC_USE_ADC3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to ADC3"
+#endif
+
+#if !defined(STM32_ENFORCE_H7_REV_XY)
+/* ADC clock source checks.*/
+#if (STM32_D1HPRE == STM32_D1HPRE_DIV1)
+#define STM32_ADC_SCLK STM32_HCLK
+#else
+#define STM32_ADC_SCLK (STM32_HCLK / 2)
+#endif
+
+#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+/* CHTODO: also check ADC_CCR_PRESC.*/
+#define STM32_ADC12_CLOCK (STM32_ADCCLK / 2)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC12_CLOCK (STM32_ADC_SCLK / 1 / 2)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC12_CLOCK (STM32_ADC_SCLK / 2 / 2)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC12_CLOCK (STM32_ADC_SCLK / 4 / 2)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE"
+#endif
+
+#if STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+/* CHTODO: also check ADC_CCR_PRESC.*/
+#define STM32_ADC3_CLOCK (STM32_ADCCLK / 2)
+#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC3_CLOCK (STM32_ADC_SCLK / 1 / 2)
+#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC3_CLOCK (STM32_ADC_SCLK / 2 / 2)
+#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC3_CLOCK (STM32_ADC_SCLK / 4 / 2)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC3_CLOCK_MODE"
+#endif
+
+#else /* defined(STM32_ENFORCE_H7_REV_XY) */
+
+#if STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC12_CLOCK STM32_ADCCLK
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC12_CLOCK (STM32_HCLK / 1)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC12_CLOCK (STM32_HCLK / 2)
+#elif STM32_ADC_ADC12_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC12_CLOCK (STM32_HCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC12_CLOCK_MODE"
+#endif
+
+#if STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_ADCCK
+#define STM32_ADC3_CLOCK STM32_ADCCLK
+#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV1
+#define STM32_ADC3_CLOCK (STM32_HCLK / 1)
+#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV2
+#define STM32_ADC3_CLOCK (STM32_HCLK / 2)
+#elif STM32_ADC_ADC3_CLOCK_MODE == ADC_CCR_CKMODE_AHB_DIV4
+#define STM32_ADC3_CLOCK (STM32_HCLK / 4)
+#else
+#error "invalid clock mode selected for STM32_ADC_ADC3_CLOCK_MODE"
+#endif
+
+#endif /* defined(STM32_ENFORCE_H7_REV_XY) */
+
+#if STM32_ADC12_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC12_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+
+#if STM32_ADC3_CLOCK > STM32_ADCCLK_MAX
+#error "STM32_ADC3_CLOCK exceeding maximum frequency (STM32_ADCCLK_MAX)"
+#endif
+
+#if !defined(STM32_ENFORCE_H7_REV_XY)
+/* ADC boost checks.*/
+#if STM32_ADC12_CLOCK > 6250000
+#define STM32_ADC12_BOOST (1U << 8U)
+#elif STM32_ADC12_CLOCK > 12500000
+#define STM32_ADC12_BOOST (2U << 8U)
+#elif STM32_ADC12_CLOCK > 25000000
+#define STM32_ADC12_BOOST (3U << 8U)
+#else
+#define STM32_ADC12_BOOST (0U << 8U)
+#endif
+
+#if STM32_ADC3_CLOCK > 6250000
+#define STM32_ADC3_BOOST (1U << 8U)
+#elif STM32_ADC3_CLOCK > 12500000
+#define STM32_ADC3_BOOST (2U << 8U)
+#elif STM32_ADC3_CLOCK > 25000000
+#define STM32_ADC3_BOOST (3U << 8U)
+#else
+#define STM32_ADC3_BOOST (0U << 8U)
+#endif
+
+#else /* defined(STM32_ENFORCE_H7_REV_XY) */
+
+#if STM32_ADC12_CLOCK > 20000000
+#define STM32_ADC12_BOOST (1U << 8U)
+#else
+#define STM32_ADC12_BOOST (0U << 8U)
+#endif
+
+#if STM32_ADC3_CLOCK > 20000000
+#define STM32_ADC3_BOOST (1U << 8U)
+#else
+#define STM32_ADC3_BOOST (0U << 8U)
+#endif
+
+#endif /* defined(STM32_ENFORCE_H7_REV_XY) */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+#if STM32_ADC_USE_ADC12
+#define STM32_ADC_DMA_REQUIRED
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+#endif
+
+#if STM32_ADC_USE_ADC3
+#define STM32_ADC_BDMA_REQUIRED
+#if !defined(STM32_BDMA_REQUIRED)
+#define STM32_BDMA_REQUIRED
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief ADC sample data type.
+ */
+#if !STM32_ADC_COMPACT_SAMPLES || defined(__DOXYGEN__)
+typedef uint16_t adcsample_t;
+#else
+typedef uint8_t adcsample_t;
+#endif
+
+/**
+ * @brief Channels number in a conversion group.
+ */
+typedef uint32_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, /**< Watchdog 1 triggered. */
+ ADC_ERR_AWD2 = 3, /**< Watchdog 2 triggered. */
+ ADC_ERR_AWD3 = 4 /**< Watchdog 3 triggered. */
+} adcerror_t;
+
+/**
+ * @brief Type of a DMA channel pointer choice.
+ */
+typedef union {
+#if defined(STM32_ADC_DMA_REQUIRED) || defined(__DOXYGEN__)
+ /**
+ * @brief DMA stream.
+ */
+ const stm32_dma_stream_t *dma;
+#endif
+#if defined(STM32_ADC_BDMA_REQUIRED) || defined(__DOXYGEN__)
+ /**
+ * @brief BDMA stream.
+ */
+ const stm32_bdma_stream_t *bdma;
+#endif
+} adc_ldd_dma_reference_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+#if STM32_ADC_USE_ADC12 == TRUE
+typedef ADC12_TypeDef ADC_TypeDef;
+#else
+typedef ADC3_TypeDef ADC_TypeDef;
+#endif
+
+/**
+ * @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; \
+ /* Calibration mode, specify ADCCALIN and/or ADCCALDIF bits in here.*/ \
+ uint32_t calibration
+
+#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 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
+ * @{
+ */
+/**
+ * @brief Number of channels in a conversion sequence.
+ */
+#define ADC_SQR1_NUM_CH(n) (((n) - 1U) << 0U)
+
+#define ADC_SQR1_SQ1_N(n) ((n) << 6U) /**< @brief 1st channel in seq. */
+#define ADC_SQR1_SQ2_N(n) ((n) << 12U)/**< @brief 2nd channel in seq. */
+#define ADC_SQR1_SQ3_N(n) ((n) << 18U)/**< @brief 3rd channel in seq. */
+#define ADC_SQR1_SQ4_N(n) ((n) << 24U)/**< @brief 4th channel in seq. */
+
+#define ADC_SQR2_SQ5_N(n) ((n) << 0U) /**< @brief 5th channel in seq. */
+#define ADC_SQR2_SQ6_N(n) ((n) << 6U) /**< @brief 6th channel in seq. */
+#define ADC_SQR2_SQ7_N(n) ((n) << 12U)/**< @brief 7th channel in seq. */
+#define ADC_SQR2_SQ8_N(n) ((n) << 18U)/**< @brief 8th channel in seq. */
+#define ADC_SQR2_SQ9_N(n) ((n) << 24U)/**< @brief 9th channel in seq. */
+
+#define ADC_SQR3_SQ10_N(n) ((n) << 0U) /**< @brief 10th channel in seq.*/
+#define ADC_SQR3_SQ11_N(n) ((n) << 6U) /**< @brief 11th channel in seq.*/
+#define ADC_SQR3_SQ12_N(n) ((n) << 12U)/**< @brief 12th channel in seq.*/
+#define ADC_SQR3_SQ13_N(n) ((n) << 18U)/**< @brief 13th channel in seq.*/
+#define ADC_SQR3_SQ14_N(n) ((n) << 24U)/**< @brief 14th channel in seq.*/
+
+#define ADC_SQR4_SQ15_N(n) ((n) << 0U) /**< @brief 15th channel in seq.*/
+#define ADC_SQR4_SQ16_N(n) ((n) << 6U) /**< @brief 16th channel in seq.*/
+/** @} */
+
+/**
+ * @name Sampling rate settings helper macros
+ * @{
+ */
+#define ADC_SMPR1_SMP_AN0(n) ((n) << 0U) /**< @brief AN0 sampling time. */
+#define ADC_SMPR1_SMP_AN1(n) ((n) << 3U) /**< @brief AN1 sampling time. */
+#define ADC_SMPR1_SMP_AN2(n) ((n) << 6U) /**< @brief AN2 sampling time. */
+#define ADC_SMPR1_SMP_AN3(n) ((n) << 9U) /**< @brief AN3 sampling time. */
+#define ADC_SMPR1_SMP_AN4(n) ((n) << 12U)/**< @brief AN4 sampling time. */
+#define ADC_SMPR1_SMP_AN5(n) ((n) << 15U)/**< @brief AN5 sampling time. */
+#define ADC_SMPR1_SMP_AN6(n) ((n) << 18U)/**< @brief AN6 sampling time. */
+#define ADC_SMPR1_SMP_AN7(n) ((n) << 21U)/**< @brief AN7 sampling time. */
+#define ADC_SMPR1_SMP_AN8(n) ((n) << 24U)/**< @brief AN8 sampling time. */
+#define ADC_SMPR1_SMP_AN9(n) ((n) << 27U)/**< @brief AN9 sampling time. */
+
+#define ADC_SMPR2_SMP_AN10(n) ((n) << 0U) /**< @brief AN10 sampling time. */
+#define ADC_SMPR2_SMP_AN11(n) ((n) << 3U) /**< @brief AN11 sampling time. */
+#define ADC_SMPR2_SMP_AN12(n) ((n) << 6U) /**< @brief AN12 sampling time. */
+#define ADC_SMPR2_SMP_AN13(n) ((n) << 9U) /**< @brief AN13 sampling time. */
+#define ADC_SMPR2_SMP_AN14(n) ((n) << 12U)/**< @brief AN14 sampling time. */
+#define ADC_SMPR2_SMP_AN15(n) ((n) << 15U)/**< @brief AN15 sampling time. */
+#define ADC_SMPR2_SMP_AN16(n) ((n) << 18U)/**< @brief AN16 sampling time. */
+#define ADC_SMPR2_SMP_AN17(n) ((n) << 21U)/**< @brief AN17 sampling time. */
+#define ADC_SMPR2_SMP_AN18(n) ((n) << 24U)/**< @brief AN18 sampling time. */
+#define ADC_SMPR2_SMP_AN19(n) ((n) << 27U)/**< @brief AN19 sampling time. */
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_ADC_USE_ADC12 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD1;
+#endif
+
+#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__)
+extern ADCDriver ADCD3;
+#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 adcSTM32EnableVREF(ADCDriver *adcp);
+ void adcSTM32DisableVREF(ADCDriver *adcp);
+ void adcSTM32EnableTS(ADCDriver *adcp);
+ void adcSTM32DisableTS(ADCDriver *adcp);
+ void adcSTM32EnableVBAT(ADCDriver *adcp);
+ void adcSTM32DisableVBAT(ADCDriver *adcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ADC */
+
+#endif /* HAL_ADC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt new file mode 100644 index 0000000..d0b59b7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv4/notes.txt @@ -0,0 +1,13 @@ +STM32 ADCv4 driver.
+
+Driver capability:
+
+- Supports the STM32 "fast" ADC found on H7 sub-family.
+
+The file registry must export:
+
+STM32_HAS_ADCx - ADCx presence flag (1..4).
+STM32_ADC12_HANDLER - IRQ vector name for ADC1 and ADC2.
+STM32_ADC12_NUMBER - IRQ vector number for ADC1 and ADC2.
+STM32_ADC34_HANDLER - IRQ vector name for ADC3 and ADC4.
+STM32_ADC34_NUMBER - IRQ vector number for ADC3 and ADC4.
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk new file mode 100644 index 0000000..1774fca --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/driver.mk @@ -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
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c new file mode 100644 index 0000000..d4d52a0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c @@ -0,0 +1,476 @@ +/*
+ 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;
+ if (grpp->error_cb != NULL) {
+ 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->AWD2CR = grpp->awd2cr;
+ adcp->adc->AWD3CR = grpp->awd3cr;
+ }
+ 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->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 */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h new file mode 100644 index 0000000..45ea1e0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.h @@ -0,0 +1,401 @@ +/*
+ 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 CHSELR register initializers for CHSELRMOD=0
+ * @{
+ */
+#define ADC_CHSELR_CHSEL_N(n) (1U << (n))
+/** @} */
+
+/**
+ * @name CHSELR register initializers for CHSELRMOD=1
+ * @{
+ */
+#define ADC_CHSELR_SQ1_N(n) ((uint32_t)(n) << 0U)
+#define ADC_CHSELR_SQ2_N(n) ((uint32_t)(n) << 4U)
+#define ADC_CHSELR_SQ3_N(n) ((uint32_t)(n) << 8U)
+#define ADC_CHSELR_SQ4_N(n) ((uint32_t)(n) << 12U)
+#define ADC_CHSELR_SQ5_N(n) ((uint32_t)(n) << 16U)
+#define ADC_CHSELR_SQ6_N(n) ((uint32_t)(n) << 20U)
+#define ADC_CHSELR_SQ7_N(n) ((uint32_t)(n) << 24U)
+#define ADC_CHSELR_SQ8_N(n) ((uint32_t)(n) << 28U)
+
+#define ADC_CHSELR_SQ1_END (15U << 0U)
+#define ADC_CHSELR_SQ2_END (15U << 4U)
+#define ADC_CHSELR_SQ3_END (15U << 8U)
+#define ADC_CHSELR_SQ4_END (15U << 12U)
+#define ADC_CHSELR_SQ5_END (15U << 16U)
+#define ADC_CHSELR_SQ6_END (15U << 20U)
+#define ADC_CHSELR_SQ7_END (15U << 24U)
+#define ADC_CHSELR_SQ8_END (15U << 28U)
+/** @} */
+
+/**
+ * @name Threshold registers initializers
+ * @{
+ */
+#define ADC_TR(low, high) (((uint32_t)(high) << 16U) | \
+ (uint32_t)(low))
+#define ADC_TR_DISABLED ADC_TR(0U, 0x0FFFU)
+#define ADC_AWDCR_ENABLE(n) (1U << (n))
+/** @} */
+
+/*===========================================================================*/
+/* 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 AWD2CR register initialization data.*/ \
+ uint32_t awd2cr; \
+ /* ADC AWD3CR register initialization data.*/ \
+ uint32_t awd3cr; \
+ /* 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 */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt new file mode 100644 index 0000000..283e5c3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/ADCv5/notes.txt @@ -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.
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk new file mode 100644 index 0000000..1146b41 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/BDMAv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt new file mode 100644 index 0000000..e7fe3ad --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/notes.txt @@ -0,0 +1,11 @@ +STM32 BDMAv1 driver.
+
+Driver capability:
+
+- The driver supports the "basic" DMA controller.
+
+The file registry must export:
+
+STM32_BDMAn_CHx_HANDLER - Vector name for IRQ "x" (1..7). If the macro
+ is not exported then the ISR is not declared.
+STM32_BDMAn_CHx_NUMBER - Vector number for IRQ "x" (1..7).
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c new file mode 100644 index 0000000..4ca2e41 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.c @@ -0,0 +1,455 @@ +/*
+ 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 BDMAv1/stm32_bdma.c
+ * @brief BDMA helper driver code.
+ *
+ * @addtogroup STM32_BDMA
+ * @details BDMA sharing helper driver. In the STM32 the BDMA streams are a
+ * shared resource, this driver allows to allocate and free BDMA
+ * streams at runtime in order to allow all the other device
+ * drivers to coordinate the access to the resource.
+ * @note The BDMA ISR handlers are all declared into this module because
+ * sharing, the various device drivers can associate a callback to
+ * ISRs when allocating streams.
+ * @{
+ */
+
+#include "hal.h"
+
+/* The following macro is only defined if some driver requiring BDMA services
+ has been enabled.*/
+#if defined(STM32_BDMA_REQUIRED) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/**
+ * @brief Mask of the BDMA streams in @p bdma_allocated_mask.
+ */
+#define STM32_BDMA_STREAMS_MASK 0x000000FFU
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief BDMA streams descriptors.
+ * @details This table keeps the association between an unique stream
+ * identifier and the involved physical registers.
+ * @note Don't use this array directly, use the appropriate wrapper macros
+ * instead: @p STM32_BDMA1_STREAM1, @p STM32_BDMA1_STREAM2 etc.
+ */
+const stm32_bdma_stream_t _stm32_bdma_streams[STM32_BDMA_STREAMS] = {
+ {BDMA, BDMA_Channel0, 0, DMAMUX2_Channel0, 0, STM32_BDMA1_CH0_NUMBER},
+ {BDMA, BDMA_Channel1, 4, DMAMUX2_Channel1, 1, STM32_BDMA1_CH1_NUMBER},
+ {BDMA, BDMA_Channel2, 8, DMAMUX2_Channel2, 2, STM32_BDMA1_CH2_NUMBER},
+ {BDMA, BDMA_Channel3, 12, DMAMUX2_Channel3, 3, STM32_BDMA1_CH3_NUMBER},
+ {BDMA, BDMA_Channel4, 16, DMAMUX2_Channel4, 4, STM32_BDMA1_CH4_NUMBER},
+ {BDMA, BDMA_Channel5, 20, DMAMUX2_Channel5, 5, STM32_BDMA1_CH5_NUMBER},
+ {BDMA, BDMA_Channel6, 24, DMAMUX2_Channel6, 6, STM32_BDMA1_CH6_NUMBER},
+ {BDMA, BDMA_Channel7, 28, DMAMUX2_Channel7, 7, STM32_BDMA1_CH7_NUMBER}
+};
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief BDMA ISR redirector type.
+ */
+typedef struct {
+ stm32_bdmaisr_t func; /**< @brief BDMA callback function. */
+ void *param; /**< @brief BDMA callback parameter.*/
+} bdma_isr_redir_t;
+
+/**
+ * @brief BDMA driver base structure.
+ */
+static struct {
+ /**
+ * @brief Mask of the allocated streams.
+ */
+ uint32_t allocated_mask;
+ /**
+ * @brief DMA IRQ redirectors.
+ */
+ struct {
+ /**
+ * @brief DMA callback function.
+ */
+ stm32_bdmaisr_t func;
+ /**
+ * @brief DMA callback parameter.
+ */
+ void *param;
+ } streams[STM32_BDMA_STREAMS];
+} bdma;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief BDMA1 stream 0 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH0_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 0U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 0U;
+ if (bdma.streams[0].func)
+ bdma.streams[0].func(bdma.streams[0].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 1 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH1_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 4U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 4U;
+ if (bdma.streams[1].func)
+ bdma.streams[1].func(bdma.streams[1].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 2 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH2_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 8U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 8U;
+ if (bdma.streams[2].func)
+ bdma.streams[2].func(bdma.streams[2].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 3 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH3_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 12U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 12U;
+ if (bdma.streams[3].func)
+ bdma.streams[3].func(bdma.streams[3].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 4 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH4_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 16U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 16U;
+ if (bdma.streams[4].func)
+ bdma.streams[4].func(bdma.streams[4].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 5 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH5_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 20U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 20U;
+ if (bdma.streams[5].func)
+ bdma.streams[5].func(bdma.streams[5].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 6 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH6_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 24U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 24U;
+ if (bdma.streams[6].func)
+ bdma.streams[6].func(bdma.streams[6].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief BDMA1 stream 7 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_BDMA1_CH7_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (BDMA->ISR >> 28U) & STM32_BDMA_ISR_MASK;
+ BDMA->IFCR = flags << 28U;
+ if (bdma.streams[7].func)
+ bdma.streams[7].func(bdma.streams[7].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 BDMA helper initialization.
+ *
+ * @init
+ */
+void bdmaInit(void) {
+ unsigned i;
+
+ bdma.allocated_mask = 0U;
+ for (i = 0; i < STM32_BDMA_STREAMS; i++) {
+ _stm32_bdma_streams[i].channel->CCR = 0U;
+ bdma.streams[i].func = NULL;
+ bdma.streams[i].param = NULL;
+ }
+ BDMA->IFCR = 0xFFFFFFFFU;
+}
+
+/**
+ * @brief Allocates a BDMA stream.
+ * @details The stream is allocated and, if required, the BDMA clock enabled.
+ * The function also enables the IRQ vector associated to the stream
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific stream or:
+ * - @p STM32_BDMA_STREAM_ID_ANY for any stream.
+ * .
+ * @param[in] priority IRQ priority for the BDMA stream
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_bdma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
+ *
+ * @iclass
+ */
+const stm32_bdma_stream_t *bdmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_bdmaisr_t func,
+ void *param) {
+ uint32_t i, startid, endid;
+
+ osalDbgCheckClassI();
+
+ if (id < STM32_BDMA_STREAMS) {
+ startid = id;
+ endid = id;
+ }
+ else if (id == STM32_BDMA_STREAM_ID_ANY) {
+ startid = 0U;
+ endid = STM32_BDMA_STREAMS - 1U;
+ }
+ else {
+ osalDbgCheck(false);
+ return NULL;
+ }
+
+ for (i = startid; i <= endid; i++) {
+ uint32_t mask = (1U << i);
+ if ((bdma.allocated_mask & mask) == 0U) {
+ const stm32_bdma_stream_t *stp = STM32_BDMA_STREAM(i);
+
+ /* Installs the DMA handler.*/
+ bdma.streams[i].func = func;
+ bdma.streams[i].param = param;
+ bdma.allocated_mask |= mask;
+
+ /* Enabling DMA clocks required by the current streams set.*/
+ if ((STM32_BDMA_STREAMS_MASK & mask) != 0U) {
+ rccEnableBDMA1(true);
+ }
+
+#if defined(rccEnableDMAMUX)
+ /* Enabling DMAMUX if present.*/
+ if (bdma.allocated_mask != 0U) {
+ rccEnableDMAMUX(true);
+ }
+#endif
+
+ /* Enables the associated IRQ vector if not already enabled and if a
+ callback is defined.*/
+ if (func != NULL) {
+ nvicEnableVector(stp->vector, priority);
+ }
+
+ /* Putting the stream in a known state.*/
+ bdmaStreamDisable(stp);
+ stp->channel->CCR = STM32_BDMA_CR_RESET_VALUE;
+
+ return stp;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Allocates a BDMA stream.
+ * @details The stream is allocated and, if required, the BDMA clock enabled.
+ * The function also enables the IRQ vector associated to the stream
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific stream or:
+ * - @p STM32_BDMA_STREAM_ID_ANY for any stream.
+ * .
+ * @param[in] priority IRQ priority for the BDMA stream
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_bdma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
+ *
+ * @api
+ */
+const stm32_bdma_stream_t *bdmaStreamAlloc(uint32_t id,
+ uint32_t priority,
+ stm32_bdmaisr_t func,
+ void *param) {
+ const stm32_bdma_stream_t *stp;
+
+ osalSysLock();
+ stp = bdmaStreamAllocI(id, priority, func, param);
+ osalSysUnlock();
+
+ return stp;
+}
+
+/**
+ * @brief Releases a BDMA stream.
+ * @details The stream is freed and, if required, the BDMA clock disabled.
+ * Trying to release a unallocated stream is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ *
+ * @iclass
+ */
+void bdmaStreamFreeI(const stm32_bdma_stream_t *stp) {
+
+ osalDbgCheck(stp != NULL);
+
+ /* Check if the streams is not taken.*/
+ osalDbgAssert((bdma.allocated_mask & (1U << stp->selfindex)) != 0U,
+ "not allocated");
+
+ /* Disables the associated IRQ vector.*/
+ nvicDisableVector(stp->vector);
+
+ /* Marks the stream as not allocated.*/
+ bdma.allocated_mask &= ~(1U << stp->selfindex);
+
+ /* Clearing associated handler and parameter.*/
+ bdma.streams->func = NULL;
+ bdma.streams->param = NULL;
+
+ /* Shutting down clocks that are no more required, if any.*/
+ if ((bdma.allocated_mask & STM32_BDMA_STREAMS_MASK) == 0U) {
+ rccDisableBDMA1();
+ }
+}
+
+/**
+ * @brief Releases a BDMA stream.
+ * @details The stream is freed and, if required, the BDMA clock disabled.
+ * Trying to release a unallocated stream is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ *
+ * @api
+ */
+void bdmaStreamFree(const stm32_bdma_stream_t *stp) {
+
+ osalSysLock();
+ bdmaStreamFreeI(stp);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Associates a peripheral request to a BDMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ *
+ * @param[in] stp pointer to a @p stm32_bdma_stream_t structure
+ * @param[in] per peripheral identifier
+ *
+ * @special
+ */
+void bdmaSetRequestSource(const stm32_bdma_stream_t *stp, uint32_t per) {
+
+ osalDbgCheck(per < 256U);
+
+ stp->mux->CCR = per;
+}
+
+#endif /* STM32_BDMA_REQUIRED */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h new file mode 100644 index 0000000..6ed63f1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/BDMAv1/stm32_bdma.h @@ -0,0 +1,441 @@ +/*
+ 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 BDMAv1/stm32_bdma.h
+ * @brief BDMA helper driver header.
+ * @note This driver uses the new naming convention used for the STM32F2xx
+ * so the "BDMA channels" are referred as "BDMA streams".
+ *
+ * @addtogroup STM32_BDMA
+ * @{
+ */
+
+#ifndef STM32_BDMA_H
+#define STM32_BDMA_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Total number of BDMA streams.
+ * @details This is the total number of streams among all the BDMA units.
+ */
+#define STM32_BDMA_STREAMS 8U
+
+/**
+ * @brief Mask of the ISR bits passed to the BDMA callback functions.
+ */
+#define STM32_BDMA_ISR_MASK 0x0EU
+
+/**
+ * @brief Checks if a BDMA priority is within the valid range.
+ *
+ * @param[in] prio BDMA priority
+ * @retval The check result.
+ * @retval false invalid BDMA priority.
+ * @retval true correct BDMA priority.
+ */
+#define STM32_BDMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U))
+
+/**
+ * @brief Checks if a BDMA stream id is within the valid range.
+ *
+ * @param[in] id BDMA stream id
+ * @retval The check result.
+ * @retval false invalid DMA stream.
+ * @retval true correct DMA stream.
+ */
+#define STM32_BDMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) <= STM32_BDMA_STREAMS))
+
+/**
+ * @name Special stream identifiers
+ * @{
+ */
+#define STM32_BDMA_STREAM_ID_ANY STM32_BDMA_STREAMS
+/** @} */
+
+/**
+ * @name BDMA streams identifiers
+ * @{
+ */
+/**
+ * @brief Returns a pointer to a stm32_dma_stream_t structure.
+ *
+ * @param[in] id the stream numeric identifier
+ * @return A pointer to the stm32_bdma_stream_t constant structure
+ * associated to the BDMA stream.
+ */
+#define STM32_BDMA_STREAM(id) (&_stm32_bdma_streams[id])
+
+#define STM32_BDMA1_STREAM0 STM32_BDMA_STREAM(0)
+#define STM32_BDMA1_STREAM1 STM32_BDMA_STREAM(1)
+#define STM32_BDMA1_STREAM2 STM32_BDMA_STREAM(2)
+#define STM32_BDMA1_STREAM3 STM32_BDMA_STREAM(3)
+#define STM32_BDMA1_STREAM4 STM32_BDMA_STREAM(4)
+#define STM32_BDMA1_STREAM5 STM32_BDMA_STREAM(5)
+#define STM32_BDMA1_STREAM6 STM32_BDMA_STREAM(6)
+#define STM32_BDMA1_STREAM7 STM32_BDMA_STREAM(7)
+/** @} */
+
+/**
+ * @name CR register constants
+ * @{
+ */
+#define STM32_BDMA_CR_RESET_VALUE 0x00000000U
+#define STM32_BDMA_CR_EN BDMA_CCR_EN_Msk
+#define STM32_BDMA_CR_TCIE BDMA_CCR_TCIE
+#define STM32_BDMA_CR_HTIE BDMA_CCR_HTIE
+#define STM32_BDMA_CR_TEIE BDMA_CCR_TEIE
+#define STM32_BDMA_CR_DIR_MASK (BDMA_CCR_DIR | BDMA_CCR_MEM2MEM)
+#define STM32_BDMA_CR_DIR_P2M 0U
+#define STM32_BDMA_CR_DIR_M2P BDMA_CCR_DIR
+#define STM32_BDMA_CR_DIR_M2M BDMA_CCR_MEM2MEM
+#define STM32_BDMA_CR_CIRC BDMA_CCR_CIRC
+#define STM32_BDMA_CR_PINC BDMA_CCR_PINC
+#define STM32_BDMA_CR_MINC BDMA_CCR_MINC
+#define STM32_BDMA_CR_PSIZE_MASK BDMA_CCR_PSIZE_Msk
+#define STM32_BDMA_CR_PSIZE_BYTE 0U
+#define STM32_BDMA_CR_PSIZE_HWORD BDMA_CCR_PSIZE_0
+#define STM32_BDMA_CR_PSIZE_WORD BDMA_CCR_PSIZE_1
+#define STM32_BDMA_CR_MSIZE_MASK BDMA_CCR_MSIZE_Msk
+#define STM32_BDMA_CR_MSIZE_BYTE 0U
+#define STM32_BDMA_CR_MSIZE_HWORD BDMA_CCR_MSIZE_0
+#define STM32_BDMA_CR_MSIZE_WORD BDMA_CCR_MSIZE_1
+#define STM32_BDMA_CR_SIZE_MASK (STM32_BDMA_CR_PSIZE_MASK | \
+ STM32_BDMA_CR_MSIZE_MASK)
+#define STM32_BDMA_CR_PL_MASK BDMA_CCR_PL_Msk
+#define STM32_BDMA_CR_PL(n) ((n) << 12U)
+#if !defined(STM32_ENFORCE_H7_REV_XY)
+#define STM32_BDMA_CR_DBM BDMA_CCR_DBM
+#define STM32_BDMA_CR_CM BDMA_CCR_CT
+#endif
+/** @} */
+
+/**
+ * @name Status flags passed to the ISR callbacks
+ * @{
+ */
+#define STM32_BDMA_ISR_TEIF BDMA_ISR_TEIF0
+#define STM32_BDMA_ISR_HTIF BDMA_ISR_HTIF0
+#define STM32_BDMA_ISR_TCIF BDMA_ISR_TCIF0
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_BDMA1)
+#error "STM32_HAS_BDMA1 missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH0_HANDLER)
+#error "STM32_BDMA1_CH0_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH1_HANDLER)
+#error "STM32_BDMA1_CH1_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH2_HANDLER)
+#error "STM32_BDMA1_CH2_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH3_HANDLER)
+#error "STM32_BDMA1_CH3_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH4_HANDLER)
+#error "STM32_BDMA1_CH4_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH5_HANDLER)
+#error "STM32_BDMA1_CH5_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH6_HANDLER)
+#error "STM32_BDMA1_CH6_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH7_HANDLER)
+#error "STM32_BDMA1_CH7_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH0_NUMBER)
+#error "STM32_BDMA1_CH0_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH1_NUMBER)
+#error "STM32_BDMA1_CH1_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH2_NUMBER)
+#error "STM32_BDMA1_CH2_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH3_NUMBER)
+#error "STM32_BDMA1_CH3_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH4_NUMBER)
+#error "STM32_BDMA1_CH4_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH5_NUMBER)
+#error "STM32_BDMA1_CH5_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH6_NUMBER)
+#error "STM32_BDMA1_CH6_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_BDMA1_CH7_NUMBER)
+#error "STM32_BDMA1_CH7_NUMBER missing in registry"
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 BDMA ISR function type.
+ *
+ * @param[in] p parameter for the registered function
+ * @param[in] flags pre-shifted content of the ISR register, the bits
+ * are aligned to bit zero
+ */
+typedef void (*stm32_bdmaisr_t)(void *p, uint32_t flags);
+
+/**
+ * @brief STM32 BDMA stream descriptor structure.
+ */
+typedef struct {
+ BDMA_TypeDef *bdma; /**< @brief Associated BDMA. */
+ BDMA_Channel_TypeDef *channel; /**< @brief Associated BDMA channel.*/
+ uint8_t shift; /**< @brief Bit offset in ISR and
+ IFCR registers. */
+ DMAMUX_Channel_TypeDef *mux; /**< @brief Associated BDMA stream. */
+ uint8_t selfindex; /**< @brief Index to self in array. */
+ uint8_t vector; /**< @brief Associated IRQ vector. */
+} stm32_bdma_stream_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Associates a peripheral data register to a BDMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ * @param[in] addr value to be written in the CPAR register
+ *
+ * @special
+ */
+#define bdmaStreamSetPeripheral(stp, addr) { \
+ (stp)->channel->CPAR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Associates a memory destination to a BDMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ * @param[in] addr value to be written in the CMAR register
+ *
+ * @special
+ */
+#define bdmaStreamSetMemory(stp, addr) { \
+ (stp)->channel->CM0AR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Sets the number of transfers to be performed.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ * @param[in] size value to be written in the CNDTR register
+ *
+ * @special
+ */
+#define bdmaStreamSetTransactionSize(stp, size) { \
+ (stp)->channel->CNDTR = (uint32_t)(size); \
+}
+
+/**
+ * @brief Returns the number of transfers to be performed.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ * @return The number of transfers to be performed.
+ *
+ * @special
+ */
+#define bdmaStreamGetTransactionSize(stp) ((size_t)((stp)->channel->CNDTR))
+
+/**
+ * @brief Programs the stream mode settings.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ * @param[in] mode value to be written in the CCR register
+ *
+ * @special
+ */
+#define bdmaStreamSetMode(stp, mode) { \
+ (stp)->channel->CCR = (uint32_t)(mode); \
+}
+
+/**
+ * @brief BDMA stream enable.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ *
+ * @special
+ */
+#define bdmaStreamEnable(stp) { \
+ (stp)->channel->CCR |= STM32_BDMA_CR_EN; \
+}
+
+/**
+ * @brief BDMA stream disable.
+ * @details The function disables the specified stream and then clears any
+ * pending interrupt.
+ * @note This function can be invoked in both ISR or thread context.
+ * @note Interrupts enabling flags are set to zero after this call, see
+ * bug 3607518.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ *
+ * @special
+ */
+#define bdmaStreamDisable(stp) { \
+ (stp)->channel->CCR &= ~(STM32_BDMA_CR_TCIE | STM32_BDMA_CR_HTIE | \
+ STM32_BDMA_CR_TEIE | STM32_BDMA_CR_EN); \
+ bdmaStreamClearInterrupt(stp); \
+}
+
+/**
+ * @brief BDMA stream interrupt sources clear.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ *
+ * @special
+ */
+#define bdmaStreamClearInterrupt(stp) { \
+ (stp)->bdma->IFCR = STM32_BDMA_ISR_MASK << (stp)->shift; \
+}
+
+/**
+ * @brief Starts a memory to memory operation using the specified stream.
+ * @note The default transfer data mode is "byte to byte" but it can be
+ * changed by specifying extra options in the @p mode parameter.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ * @param[in] mode value to be written in the CCR register, this value
+ * is implicitly ORed with:
+ * - @p STM32_BDMA_CR_MINC
+ * - @p STM32_BDMA_CR_PINC
+ * - @p STM32_BDMA_CR_DIR_M2M
+ * - @p STM32_BDMA_CR_EN
+ * .
+ * @param[in] src source address
+ * @param[in] dst destination address
+ * @param[in] n number of data units to copy
+ */
+#define bdmaStartMemCopy(stp, mode, src, dst, n) { \
+ bdmaStreamSetPeripheral(stp, src); \
+ bdmaStreamSetMemory0(stp, dst); \
+ bdmaStreamSetTransactionSize(stp, n); \
+ bdmaStreamSetMode(stp, (mode) | \
+ STM32_BDMA_CR_MINC | STM32_BDMA_CR_PINC | \
+ STM32_BDMA_CR_DIR_M2M | STM32_BDMA_CR_EN); \
+}
+
+/**
+ * @brief Polled wait for BDMA transfer end.
+ * @pre The stream must have been allocated using @p bdmaStreamAllocate().
+ * @post After use the stream can be released using @p bdmaStreamRelease().
+ *
+ * @param[in] stp pointer to an @p stm32_bdma_stream_t structure
+ */
+#define bdmaWaitCompletion(stp) { \
+ while ((stp)->channel->CNDTR > 0U) \
+ ; \
+ bdmaStreamDisable(stp); \
+}
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern const stm32_bdma_stream_t _stm32_bdma_streams[STM32_BDMA_STREAMS];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void bdmaInit(void);
+ const stm32_bdma_stream_t *bdmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_bdmaisr_t func,
+ void *param);
+ const stm32_bdma_stream_t *bdmaStreamAlloc(uint32_t id,
+ uint32_t priority,
+ stm32_bdmaisr_t func,
+ void *param);
+ void bdmaStreamFreeI(const stm32_bdma_stream_t *stp);
+ void bdmaStreamFree(const stm32_bdma_stream_t *stp);
+ void bdmaSetRequestSource(const stm32_bdma_stream_t *stp, uint32_t per);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_BDMA_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk new file mode 100644 index 0000000..608a927 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c new file mode 100644 index 0000000..4d4e76a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c @@ -0,0 +1,1032 @@ +/*
+ 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 CANv1/hal_can_lld.c
+ * @brief STM32 CAN subsystem low level driver source.
+ *
+ * @addtogroup CAN
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*
+ * Addressing differences in the headers, they seem unable to agree on names.
+ */
+#if STM32_CAN_USE_CAN1
+#if !defined(CAN1)
+#define CAN1 CAN
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief CAN1 driver identifier.*/
+#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__)
+CANDriver CAND1;
+#endif
+
+/** @brief CAN2 driver identifier.*/
+#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__)
+CANDriver CAND2;
+#endif
+
+/** @brief CAN3 driver identifier.*/
+#if STM32_CAN_USE_CAN3 || defined(__DOXYGEN__)
+CANDriver CAND3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+/**
+ * @brief Programs the filters of CAN 1 and CAN 2.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] can2sb number of the first filter assigned to CAN2
+ * @param[in] num number of entries in the filters array, if zero then
+ * a default filter is programmed
+ * @param[in] cfp pointer to the filters array, can be @p NULL if
+ * (num == 0)
+ *
+ * @notapi
+ */
+static void can_lld_set_filters(CANDriver* canp,
+ uint32_t can2sb,
+ uint32_t num,
+ const CANFilter *cfp) {
+
+#if STM32_CAN_USE_CAN2
+ if (canp == &CAND2) {
+ /* Set handle to CAN1, because CAN1 manages the filters of CAN2.*/
+ canp = &CAND1;
+ }
+#endif
+
+ /* Temporarily enabling CAN clock.*/
+#if STM32_CAN_USE_CAN1
+ if (canp == &CAND1) {
+ rccEnableCAN1(true);
+ /* Filters initialization.*/
+ canp->can->FMR = (canp->can->FMR & 0xFFFF0000) | CAN_FMR_FINIT;
+ canp->can->FMR = (canp->can->FMR & 0xFFFF0000) | (can2sb << 8) | CAN_FMR_FINIT;
+ }
+#endif
+
+#if STM32_CAN_USE_CAN3
+ if (canp == &CAND3) {
+ rccEnableCAN3(true);
+ /* Filters initialization.*/
+ canp->can->FMR = (canp->can->FMR & 0xFFFF0000) | CAN_FMR_FINIT;
+ }
+#endif
+
+ if (num > 0) {
+ uint32_t i, fmask;
+
+ /* All filters cleared.*/
+ canp->can->FA1R = 0;
+ canp->can->FM1R = 0;
+ canp->can->FS1R = 0;
+ canp->can->FFA1R = 0;
+
+#if STM32_CAN_USE_CAN1
+ if (canp == &CAND1) {
+ for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) {
+ canp->can->sFilterRegister[i].FR1 = 0;
+ canp->can->sFilterRegister[i].FR2 = 0;
+ }
+ }
+#endif
+
+#if STM32_CAN_USE_CAN3
+ if (canp == &CAND3) {
+ for (i = 0; i < STM32_CAN3_MAX_FILTERS; i++) {
+ canp->can->sFilterRegister[i].FR1 = 0;
+ canp->can->sFilterRegister[i].FR2 = 0;
+ }
+ }
+#endif
+
+ /* Scanning the filters array.*/
+ for (i = 0; i < num; i++) {
+ fmask = 1 << cfp->filter;
+ if (cfp->mode)
+ canp->can->FM1R |= fmask;
+ if (cfp->scale)
+ canp->can->FS1R |= fmask;
+ if (cfp->assignment)
+ canp->can->FFA1R |= fmask;
+ canp->can->sFilterRegister[cfp->filter].FR1 = cfp->register1;
+ canp->can->sFilterRegister[cfp->filter].FR2 = cfp->register2;
+ canp->can->FA1R |= fmask;
+ cfp++;
+ }
+ }
+ else {
+ /* Setting up a single default filter that enables everything for both
+ CANs.*/
+ canp->can->sFilterRegister[0].FR1 = 0;
+ canp->can->sFilterRegister[0].FR2 = 0;
+#if STM32_CAN_USE_CAN2
+ if (canp == &CAND1) {
+ canp->can->sFilterRegister[can2sb].FR1 = 0;
+ canp->can->sFilterRegister[can2sb].FR2 = 0;
+ }
+#endif
+ canp->can->FM1R = 0;
+ canp->can->FFA1R = 0;
+ canp->can->FS1R = 1;
+ canp->can->FA1R = 1;
+#if STM32_CAN_USE_CAN2
+ if (canp == &CAND1) {
+ canp->can->FS1R |= 1 << can2sb;
+ canp->can->FA1R |= 1 << can2sb;
+ }
+#endif
+ }
+ canp->can->FMR &= ~CAN_FMR_FINIT;
+
+ /* Clock disabled, it will be enabled again in can_lld_start().*/
+ /* Temporarily enabling CAN clock.*/
+#if STM32_CAN_USE_CAN1
+ if (canp == &CAND1) {
+ rccDisableCAN1();
+ }
+#endif
+#if STM32_CAN_USE_CAN3
+ if (canp == &CAND3) {
+ rccDisableCAN3();
+ }
+#endif
+}
+
+/**
+ * @brief Common TX ISR handler.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+static void can_lld_tx_handler(CANDriver *canp) {
+ uint32_t tsr;
+ eventflags_t flags;
+
+ /* Clearing IRQ sources.*/
+ tsr = canp->can->TSR;
+ canp->can->TSR = tsr;
+
+ /* Flags to be signaled through the TX event source.*/
+ flags = 0U;
+
+ /* Checking mailbox 0.*/
+ if ((tsr & CAN_TSR_RQCP0) != 0U) {
+ if ((tsr & (CAN_TSR_ALST0 | CAN_TSR_TERR0)) != 0U) {
+ flags |= CAN_MAILBOX_TO_MASK(1U) << 16U;
+ }
+ else {
+ flags |= CAN_MAILBOX_TO_MASK(1U);
+ }
+ }
+
+ /* Checking mailbox 1.*/
+ if ((tsr & CAN_TSR_RQCP1) != 0U) {
+ if ((tsr & (CAN_TSR_ALST1 | CAN_TSR_TERR1)) != 0U) {
+ flags |= CAN_MAILBOX_TO_MASK(2U) << 16U;
+ }
+ else {
+ flags |= CAN_MAILBOX_TO_MASK(2U);
+ }
+ }
+
+ /* Checking mailbox 2.*/
+ if ((tsr & CAN_TSR_RQCP2) != 0U) {
+ if ((tsr & (CAN_TSR_ALST2 | CAN_TSR_TERR2)) != 0U) {
+ flags |= CAN_MAILBOX_TO_MASK(3U) << 16U;
+ }
+ else {
+ flags |= CAN_MAILBOX_TO_MASK(3U);
+ }
+ }
+
+ /* Signaling flags and waking up threads waiting for a transmission slot.*/
+ _can_tx_empty_isr(canp, flags);
+}
+
+/**
+ * @brief Common RX0 ISR handler.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+static void can_lld_rx0_handler(CANDriver *canp) {
+ uint32_t rf0r;
+
+ rf0r = canp->can->RF0R;
+ if ((rf0r & CAN_RF0R_FMP0) > 0) {
+ /* No more receive events until the queue 0 has been emptied.*/
+ canp->can->IER &= ~CAN_IER_FMPIE0;
+ _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(1U));
+ }
+ if ((rf0r & CAN_RF0R_FOVR0) > 0) {
+ /* Overflow events handling.*/
+ canp->can->RF0R = CAN_RF0R_FOVR0;
+ _can_error_isr(canp, CAN_OVERFLOW_ERROR);
+ }
+}
+
+/**
+ * @brief Common RX1 ISR handler.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+static void can_lld_rx1_handler(CANDriver *canp) {
+ uint32_t rf1r;
+
+ rf1r = canp->can->RF1R;
+ if ((rf1r & CAN_RF1R_FMP1) > 0) {
+ /* No more receive events until the queue 0 has been emptied.*/
+ canp->can->IER &= ~CAN_IER_FMPIE1;
+ _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(2U));
+ }
+ if ((rf1r & CAN_RF1R_FOVR1) > 0) {
+ /* Overflow events handling.*/
+ canp->can->RF1R = CAN_RF1R_FOVR1;
+ _can_error_isr(canp, CAN_OVERFLOW_ERROR);
+ }
+}
+
+/**
+ * @brief Common SCE ISR handler.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+static void can_lld_sce_handler(CANDriver *canp) {
+ uint32_t msr;
+
+ /* Clearing IRQ sources.*/
+ msr = canp->can->MSR;
+ canp->can->MSR = msr;
+
+ /* Wakeup event.*/
+#if CAN_USE_SLEEP_MODE
+ if (msr & CAN_MSR_WKUI) {
+ canp->state = CAN_READY;
+ canp->can->MCR &= ~CAN_MCR_SLEEP;
+ _can_wakeup_isr(canp);
+ }
+#endif /* CAN_USE_SLEEP_MODE */
+ /* Error event.*/
+ if (msr & CAN_MSR_ERRI) {
+ eventflags_t flags;
+ uint32_t esr = canp->can->ESR;
+
+#if STM32_CAN_REPORT_ALL_ERRORS
+ flags = (eventflags_t)(esr & 7);
+ if ((esr & CAN_ESR_LEC) > 0)
+ flags |= CAN_FRAMING_ERROR;
+#else
+ flags = 0;
+#endif
+
+ /* The content of the ESR register is copied unchanged in the upper
+ half word of the listener flags mask.*/
+ _can_error_isr(canp, flags | (eventflags_t)(esr << 16U));
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__)
+#if defined(STM32_CAN1_UNIFIED_HANDLER)
+/**
+ * @brief CAN1 unified interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN1_UNIFIED_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND1);
+ can_lld_rx0_handler(&CAND1);
+ can_lld_rx1_handler(&CAND1);
+ can_lld_sce_handler(&CAND1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#else /* !defined(STM32_CAN1_UNIFIED_HANDLER) */
+
+#if !defined(STM32_CAN1_TX_HANDLER)
+#error "STM32_CAN1_TX_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN1_RX0_HANDLER)
+#error "STM32_CAN1_RX0_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN1_RX1_HANDLER)
+#error "STM32_CAN1_RX1_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN1_SCE_HANDLER)
+#error "STM32_CAN1_SCE_HANDLER not defined"
+#endif
+
+/**
+ * @brief CAN1 TX interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN1 RX0 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_rx0_handler(&CAND1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN1 RX1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_rx1_handler(&CAND1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN1 SCE interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_sce_handler(&CAND1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_CAN1_UNIFIED_HANDLER) */
+#endif /* STM32_CAN_USE_CAN1 */
+
+#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__)
+#if defined(STM32_CAN2_UNIFIED_HANDLER)
+/**
+ * @brief CAN1 unified interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN2_UNIFIED_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND2);
+ can_lld_rx0_handler(&CAND2);
+ can_lld_rx1_handler(&CAND2);
+ can_lld_sce_handler(&CAND2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#else /* !defined(STM32_CAN2_UNIFIED_HANDLER) */
+
+#if !defined(STM32_CAN1_TX_HANDLER)
+#error "STM32_CAN1_TX_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN1_RX0_HANDLER)
+#error "STM32_CAN1_RX0_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN1_RX1_HANDLER)
+#error "STM32_CAN1_RX1_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN1_SCE_HANDLER)
+#error "STM32_CAN1_SCE_HANDLER not defined"
+#endif
+
+/**
+ * @brief CAN2 TX interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN2_TX_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN2 RX0 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN2_RX0_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_rx0_handler(&CAND2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN2 RX1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN2_RX1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_rx1_handler(&CAND2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN2 SCE interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN2_SCE_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_sce_handler(&CAND2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_CAN2_UNIFIED_HANDLER) */
+#endif /* STM32_CAN_USE_CAN2 */
+
+#if STM32_CAN_USE_CAN3 || defined(__DOXYGEN__)
+#if defined(STM32_CAN3_UNIFIED_HANDLER)
+/**
+ * @brief CAN1 unified interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN3_UNIFIED_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND3);
+ can_lld_rx0_handler(&CAND3);
+ can_lld_rx1_handler(&CAND3);
+ can_lld_sce_handler(&CAND3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#else /* !defined(STM32_CAN3_UNIFIED_HANDLER) */
+
+#if !defined(STM32_CAN3_TX_HANDLER)
+#error "STM32_CAN3_TX_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN3_RX0_HANDLER)
+#error "STM32_CAN3_RX0_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN3_RX1_HANDLER)
+#error "STM32_CAN3_RX1_HANDLER not defined"
+#endif
+#if !defined(STM32_CAN3_SCE_HANDLER)
+#error "STM32_CAN3_SCE_HANDLER not defined"
+#endif
+
+/**
+ * @brief CAN3 TX interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN3_TX_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN3 RX0 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN3_RX0_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_rx0_handler(&CAND3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN1 RX3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN3_RX1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_rx1_handler(&CAND3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN1 SCE interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_CAN3_SCE_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ can_lld_sce_handler(&CAND3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_CAN1_UNIFIED_HANDLER) */
+#endif /* STM32_CAN_USE_CAN1 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level CAN driver initialization.
+ *
+ * @notapi
+ */
+void can_lld_init(void) {
+
+#if STM32_CAN_USE_CAN1
+ /* Driver initialization.*/
+ canObjectInit(&CAND1);
+ CAND1.can = CAN1;
+#if defined(STM32_CAN1_UNIFIED_NUMBER)
+ nvicEnableVector(STM32_CAN1_UNIFIED_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+#else
+ nvicEnableVector(STM32_CAN1_TX_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN1_RX0_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN1_RX1_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN1_SCE_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_CAN_USE_CAN2
+ /* Driver initialization.*/
+ canObjectInit(&CAND2);
+ CAND2.can = CAN2;
+#if defined(STM32_CAN2_UNIFIED_NUMBER)
+ nvicEnableVector(STM32_CAN2_UNIFIED_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+#else
+ nvicEnableVector(STM32_CAN2_TX_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN2_RX0_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN2_RX1_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN2_SCE_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_CAN_USE_CAN3
+ /* Driver initialization.*/
+ canObjectInit(&CAND3);
+ CAND3.can = CAN3;
+#if defined(STM32_CAN3_UNIFIED_NUMBER)
+ nvicEnableVector(STM32_CAN3_UNIFIED_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+#else
+ nvicEnableVector(STM32_CAN3_TX_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN3_RX0_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN3_RX1_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN3_SCE_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+#endif
+#endif
+
+ /* Filters initialization.*/
+#if STM32_CAN_USE_CAN1
+#if STM32_HAS_CAN2
+ can_lld_set_filters(&CAND1, STM32_CAN_MAX_FILTERS / 2, 0, NULL);
+#else
+ can_lld_set_filters(&CAND1, STM32_CAN_MAX_FILTERS, 0, NULL);
+#endif
+#endif
+
+#if STM32_HAS_CAN3
+#if STM32_CAN_USE_CAN3
+ can_lld_set_filters(&CAND3, STM32_CAN3_MAX_FILTERS, 0, NULL);
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the CAN peripheral.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_start(CANDriver *canp) {
+
+ /* Clock activation.*/
+#if STM32_CAN_USE_CAN1
+ if (&CAND1 == canp) {
+ rccEnableCAN1(true);
+ }
+#endif
+
+#if STM32_CAN_USE_CAN2
+ if (&CAND2 == canp) {
+ rccEnableCAN1(true); /* CAN 2 requires CAN1, so enabling it first.*/
+ rccEnableCAN2(true);
+ }
+#endif
+
+#if STM32_CAN_USE_CAN3
+ if (&CAND3 == canp) {
+ rccEnableCAN3(true);
+ }
+#endif
+
+ /* Configuring CAN. */
+ canp->can->MCR = CAN_MCR_INRQ;
+ while ((canp->can->MSR & CAN_MSR_INAK) == 0)
+ osalThreadSleepS(1);
+ canp->can->BTR = canp->config->btr;
+ canp->can->MCR = canp->config->mcr;
+
+ /* Interrupt sources initialization.*/
+#if STM32_CAN_REPORT_ALL_ERRORS
+ canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 |
+ CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE |
+ CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE |
+ CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
+#else
+ canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 |
+ CAN_IER_WKUIE | CAN_IER_ERRIE |
+ CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE |
+ CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
+#endif
+}
+
+/**
+ * @brief Deactivates the CAN peripheral.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_stop(CANDriver *canp) {
+
+ /* If in ready state then disables the CAN peripheral.*/
+ if (canp->state == CAN_READY) {
+#if STM32_CAN_USE_CAN1
+ if (&CAND1 == canp) {
+ CAN1->MCR = 0x00010002; /* Register reset value. */
+ CAN1->IER = 0x00000000; /* All sources disabled. */
+#if STM32_CAN_USE_CAN2
+ /* If CAND2 is stopped then CAN1 clock is stopped here.*/
+ if (CAND2.state == CAN_STOP)
+#endif
+ {
+ rccDisableCAN1();
+ }
+ }
+#endif
+
+#if STM32_CAN_USE_CAN2
+ if (&CAND2 == canp) {
+ CAN2->MCR = 0x00010002; /* Register reset value. */
+ CAN2->IER = 0x00000000; /* All sources disabled. */
+#if STM32_CAN_USE_CAN1
+ /* If CAND1 is stopped then CAN1 clock is stopped here.*/
+ if (CAND1.state == CAN_STOP)
+#endif
+ {
+ rccDisableCAN1();
+ }
+ rccDisableCAN2();
+ }
+#endif
+
+#if STM32_CAN_USE_CAN3
+ if (&CAND3 == canp) {
+ CAN3->MCR = 0x00010002; /* Register reset value. */
+ CAN3->IER = 0x00000000; /* All sources disabled. */
+ rccDisableCAN3();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Determines whether a frame can be transmitted.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ *
+ * @return The queue space availability.
+ * @retval false no space in the transmit queue.
+ * @retval true transmit slot available.
+ *
+ * @notapi
+ */
+bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) {
+
+ switch (mailbox) {
+ case CAN_ANY_MAILBOX:
+ return (canp->can->TSR & CAN_TSR_TME) != 0;
+ case 1:
+ return (canp->can->TSR & CAN_TSR_TME0) != 0;
+ case 2:
+ return (canp->can->TSR & CAN_TSR_TME1) != 0;
+ case 3:
+ return (canp->can->TSR & CAN_TSR_TME2) != 0;
+ default:
+ return false;
+ }
+}
+
+/**
+ * @brief Inserts a frame into the transmit queue.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] ctfp pointer to the CAN frame to be transmitted
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ *
+ * @notapi
+ */
+void can_lld_transmit(CANDriver *canp,
+ canmbx_t mailbox,
+ const CANTxFrame *ctfp) {
+ uint32_t tir;
+ CAN_TxMailBox_TypeDef *tmbp;
+
+ /* Pointer to a free transmission mailbox.*/
+ switch (mailbox) {
+ case CAN_ANY_MAILBOX:
+ tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24];
+ break;
+ case 1:
+ tmbp = &canp->can->sTxMailBox[0];
+ break;
+ case 2:
+ tmbp = &canp->can->sTxMailBox[1];
+ break;
+ case 3:
+ tmbp = &canp->can->sTxMailBox[2];
+ break;
+ default:
+ return;
+ }
+
+ /* Preparing the message.*/
+ if (ctfp->IDE)
+ tir = ((uint32_t)ctfp->EID << 3) | ((uint32_t)ctfp->RTR << 1) |
+ CAN_TI0R_IDE;
+ else
+ tir = ((uint32_t)ctfp->SID << 21) | ((uint32_t)ctfp->RTR << 1);
+ tmbp->TDTR = ctfp->DLC;
+ tmbp->TDLR = ctfp->data32[0];
+ tmbp->TDHR = ctfp->data32[1];
+ tmbp->TIR = tir | CAN_TI0R_TXRQ;
+}
+
+/**
+ * @brief Determines whether a frame has been received.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ *
+ * @return The queue space availability.
+ * @retval false no space in the transmit queue.
+ * @retval true transmit slot available.
+ *
+ * @notapi
+ */
+bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) {
+
+ switch (mailbox) {
+ case CAN_ANY_MAILBOX:
+ return ((canp->can->RF0R & CAN_RF0R_FMP0) != 0 ||
+ (canp->can->RF1R & CAN_RF1R_FMP1) != 0);
+ case 1:
+ return (canp->can->RF0R & CAN_RF0R_FMP0) != 0;
+ case 2:
+ return (canp->can->RF1R & CAN_RF1R_FMP1) != 0;
+ default:
+ return false;
+ }
+}
+
+/**
+ * @brief Receives a frame from the input queue.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ * @param[out] crfp pointer to the buffer where the CAN frame is copied
+ *
+ * @notapi
+ */
+void can_lld_receive(CANDriver *canp,
+ canmbx_t mailbox,
+ CANRxFrame *crfp) {
+ uint32_t rir, rdtr;
+
+ if (mailbox == CAN_ANY_MAILBOX) {
+ if ((canp->can->RF0R & CAN_RF0R_FMP0) != 0)
+ mailbox = 1;
+ else if ((canp->can->RF1R & CAN_RF1R_FMP1) != 0)
+ mailbox = 2;
+ else {
+ /* Should not happen, do nothing.*/
+ return;
+ }
+ }
+ switch (mailbox) {
+ case 1:
+ /* Fetches the message.*/
+ rir = canp->can->sFIFOMailBox[0].RIR;
+ rdtr = canp->can->sFIFOMailBox[0].RDTR;
+ crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR;
+ crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR;
+
+ /* Releases the mailbox.*/
+ canp->can->RF0R = CAN_RF0R_RFOM0;
+
+ /* If the queue is empty re-enables the interrupt in order to generate
+ events again.*/
+ if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0)
+ canp->can->IER |= CAN_IER_FMPIE0;
+ break;
+ case 2:
+ /* Fetches the message.*/
+ rir = canp->can->sFIFOMailBox[1].RIR;
+ rdtr = canp->can->sFIFOMailBox[1].RDTR;
+ crfp->data32[0] = canp->can->sFIFOMailBox[1].RDLR;
+ crfp->data32[1] = canp->can->sFIFOMailBox[1].RDHR;
+
+ /* Releases the mailbox.*/
+ canp->can->RF1R = CAN_RF1R_RFOM1;
+
+ /* If the queue is empty re-enables the interrupt in order to generate
+ events again.*/
+ if ((canp->can->RF1R & CAN_RF1R_FMP1) == 0)
+ canp->can->IER |= CAN_IER_FMPIE1;
+ break;
+ default:
+ /* Should not happen, do nothing.*/
+ return;
+ }
+
+ /* Decodes the various fields in the RX frame.*/
+ crfp->RTR = (rir & CAN_RI0R_RTR) >> 1;
+ crfp->IDE = (rir & CAN_RI0R_IDE) >> 2;
+ if (crfp->IDE)
+ crfp->EID = rir >> 3;
+ else
+ crfp->SID = rir >> 21;
+ crfp->DLC = rdtr & CAN_RDT0R_DLC;
+ crfp->FMI = (uint8_t)(rdtr >> 8);
+ crfp->TIME = (uint16_t)(rdtr >> 16);
+}
+
+/**
+ * @brief Tries to abort an ongoing transmission.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number
+ *
+ * @notapi
+ */
+void can_lld_abort(CANDriver *canp,
+ canmbx_t mailbox) {
+
+ canp->can->TSR = 128U << ((mailbox - 1U) * 8U);
+}
+
+#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
+/**
+ * @brief Enters the sleep mode.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_sleep(CANDriver *canp) {
+
+ canp->can->MCR |= CAN_MCR_SLEEP;
+}
+
+/**
+ * @brief Enforces leaving the sleep mode.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_wakeup(CANDriver *canp) {
+
+ canp->can->MCR &= ~CAN_MCR_SLEEP;
+}
+#endif /* CAN_USE_SLEEP_MODE */
+
+/**
+ * @brief Programs the filters.
+ * @note This is an STM32-specific API.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] can2sb number of the first filter assigned to CAN2
+ * @param[in] num number of entries in the filters array, if zero then
+ * a default filter is programmed
+ * @param[in] cfp pointer to the filters array, can be @p NULL if
+ * (num == 0)
+ *
+ * @api
+ */
+void canSTM32SetFilters(CANDriver *canp, uint32_t can2sb,
+ uint32_t num, const CANFilter *cfp) {
+
+#if STM32_CAN_USE_CAN2
+ osalDbgCheck((can2sb <= STM32_CAN_MAX_FILTERS) &&
+ (num <= STM32_CAN_MAX_FILTERS));
+#endif
+
+#if STM32_CAN_USE_CAN1
+ osalDbgAssert(CAND1.state == CAN_STOP, "invalid state");
+#endif
+#if STM32_CAN_USE_CAN2
+ osalDbgAssert(CAND2.state == CAN_STOP, "invalid state");
+#endif
+#if STM32_CAN_USE_CAN3
+ osalDbgAssert(CAND3.state == CAN_STOP, "invalid state");
+#endif
+
+#if STM32_CAN_USE_CAN1
+ if (canp == &CAND1) {
+ can_lld_set_filters(canp, can2sb, num, cfp);
+ }
+#endif
+#if STM32_CAN_USE_CAN3
+ if (canp == &CAND3) {
+ can_lld_set_filters(canp, can2sb, num, cfp);
+ }
+#endif
+}
+
+#endif /* HAL_USE_CAN */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h new file mode 100644 index 0000000..e4eb6f6 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h @@ -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 CANv1/hal_can_lld.h
+ * @brief STM32 CAN subsystem low level driver header.
+ *
+ * @addtogroup CAN
+ * @{
+ */
+
+#ifndef HAL_CAN_LLD_H
+#define HAL_CAN_LLD_H
+
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*
+ * The following macros from the ST header file are replaced with better
+ * equivalents.
+ */
+#undef CAN_BTR_BRP
+#undef CAN_BTR_TS1
+#undef CAN_BTR_TS2
+#undef CAN_BTR_SJW
+
+/**
+ * @brief This switch defines whether the driver implementation supports
+ * a low power switch mode with automatic an wakeup feature.
+ */
+#define CAN_SUPPORTS_SLEEP TRUE
+
+/**
+ * @brief This implementation supports three transmit mailboxes.
+ */
+#define CAN_TX_MAILBOXES 3
+
+/**
+ * @brief This implementation supports two receive mailboxes.
+ */
+#define CAN_RX_MAILBOXES 2
+
+/**
+ * @name CAN registers helper macros
+ * @{
+ */
+#define CAN_BTR_BRP(n) (n) /**< @brief BRP field macro.*/
+#define CAN_BTR_TS1(n) ((n) << 16) /**< @brief TS1 field macro.*/
+#define CAN_BTR_TS2(n) ((n) << 20) /**< @brief TS2 field macro.*/
+#define CAN_BTR_SJW(n) ((n) << 24) /**< @brief SJW field macro.*/
+
+#define CAN_IDE_STD 0 /**< @brief Standard id. */
+#define CAN_IDE_EXT 1 /**< @brief Extended id. */
+
+#define CAN_RTR_DATA 0 /**< @brief Data frame. */
+#define CAN_RTR_REMOTE 1 /**< @brief Remote frame. */
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief CAN pedantic errors report.
+ * @details Use of this option is IRQ-intensive.
+ */
+#if !defined(STM32_CAN_REPORT_ALL_ERRORS) || defined(__DOXYGEN__)
+#define STM32_CAN_REPORT_ALL_ERRORS FALSE
+#endif
+
+/**
+ * @brief CAN1 driver enable switch.
+ * @details If set to @p TRUE the support for CAN1 is included.
+ */
+#if !defined(STM32_CAN_USE_CAN1) || defined(__DOXYGEN__)
+#define STM32_CAN_USE_CAN1 FALSE
+#endif
+
+/**
+ * @brief CAN2 driver enable switch.
+ * @details If set to @p TRUE the support for CAN2 is included.
+ */
+#if !defined(STM32_CAN_USE_CAN2) || defined(__DOXYGEN__)
+#define STM32_CAN_USE_CAN2 FALSE
+#endif
+
+/**
+ * @brief CAN3 driver enable switch.
+ * @details If set to @p TRUE the support for CAN3 is included.
+ */
+#if !defined(STM32_CAN_USE_CAN3) || defined(__DOXYGEN__)
+#define STM32_CAN_USE_CAN3 FALSE
+#endif
+
+/**
+ * @brief CAN1 interrupt priority level setting.
+ */
+#if !defined(STM32_CAN_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CAN_CAN1_IRQ_PRIORITY 11
+#endif
+/** @} */
+
+/**
+ * @brief CAN2 interrupt priority level setting.
+ */
+#if !defined(STM32_CAN_CAN2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CAN_CAN2_IRQ_PRIORITY 11
+#endif
+/** @} */
+
+/**
+ * @brief CAN3 interrupt priority level setting.
+ */
+#if !defined(STM32_CAN_CAN3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CAN_CAN3_IRQ_PRIORITY 11
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_CAN1)
+#error "STM32_HAS_CAN1 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_CAN2)
+#error "STM32_HAS_CAN2 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_CAN3)
+#error "STM32_HAS_CAN3 not defined in registry"
+#endif
+
+#if (STM32_HAS_CAN1 | STM32_HAS_CAN2) && !defined(STM32_CAN_MAX_FILTERS)
+#error "STM32_CAN_MAX_FILTERS not defined in registry"
+#endif
+
+#if STM32_HAS_CAN3 && !defined(STM32_CAN3_MAX_FILTERS)
+#error "STM32_CAN3_MAX_FILTERS not defined in registry"
+#endif
+
+#if STM32_CAN_USE_CAN1 && !STM32_HAS_CAN1
+#error "CAN1 not present in the selected device"
+#endif
+
+#if STM32_CAN_USE_CAN2 && !STM32_HAS_CAN2
+#error "CAN2 not present in the selected device"
+#endif
+
+#if STM32_CAN_USE_CAN3 && !STM32_HAS_CAN3
+#error "CAN2 not present in the selected device"
+#endif
+
+#if !STM32_CAN_USE_CAN1 && !STM32_CAN_USE_CAN2 && !STM32_CAN_USE_CAN3
+#error "CAN driver activated but no CAN peripheral assigned"
+#endif
+
+#if !STM32_CAN_USE_CAN1 && STM32_CAN_USE_CAN2
+#error "CAN2 requires CAN1, it cannot operate independently"
+#endif
+
+#if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP
+#error "CAN sleep mode not supported in this architecture"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an CAN driver.
+ */
+typedef struct CANDriver CANDriver;
+
+/**
+ * @brief Type of a transmission mailbox index.
+ */
+typedef uint32_t canmbx_t;
+
+#if (CAN_ENFORCE_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a CAN notification callback.
+ *
+ * @param[in] canp pointer to the @p CANDriver object triggering the
+ * callback
+ * @param[in] flags flags associated to the mailbox callback
+ */
+typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags);
+#endif
+
+/**
+ * @brief CAN transmission frame.
+ * @note Accessing the frame data as word16 or word32 is not portable because
+ * machine data endianness, it can be still useful for a quick filling.
+ */
+typedef struct {
+ struct {
+ uint8_t DLC:4; /**< @brief Data length. */
+ uint8_t RTR:1; /**< @brief Frame type. */
+ uint8_t IDE:1; /**< @brief Identifier type. */
+ };
+ union {
+ struct {
+ uint32_t SID:11; /**< @brief Standard identifier.*/
+ };
+ struct {
+ uint32_t EID:29; /**< @brief Extended identifier.*/
+ };
+ };
+ union {
+ uint8_t data8[8]; /**< @brief Frame data. */
+ uint16_t data16[4]; /**< @brief Frame data. */
+ uint32_t data32[2]; /**< @brief Frame data. */
+ uint64_t data64[1]; /**< @brief Frame data. */
+ };
+} CANTxFrame;
+
+/**
+ * @brief CAN received frame.
+ * @note Accessing the frame data as word16 or word32 is not portable because
+ * machine data endianness, it can be still useful for a quick filling.
+ */
+typedef struct {
+ struct {
+ uint8_t FMI; /**< @brief Filter id. */
+ uint16_t TIME; /**< @brief Time stamp. */
+ };
+ struct {
+ uint8_t DLC:4; /**< @brief Data length. */
+ uint8_t RTR:1; /**< @brief Frame type. */
+ uint8_t IDE:1; /**< @brief Identifier type. */
+ };
+ union {
+ struct {
+ uint32_t SID:11; /**< @brief Standard identifier.*/
+ };
+ struct {
+ uint32_t EID:29; /**< @brief Extended identifier.*/
+ };
+ };
+ union {
+ uint8_t data8[8]; /**< @brief Frame data. */
+ uint16_t data16[4]; /**< @brief Frame data. */
+ uint32_t data32[2]; /**< @brief Frame data. */
+ uint64_t data64[1]; /**< @brief Frame data. */
+ };
+} CANRxFrame;
+
+/**
+ * @brief CAN filter.
+ * @note Refer to the STM32 reference manual for info about filters.
+ */
+typedef struct {
+ /**
+ * @brief Number of the filter bank to be programmed.
+ */
+ uint32_t filter:16;
+ /**
+ * @brief Filter mode.
+ * @note This bit represent the CAN_FM1R register bit associated to this
+ * filter (0=mask mode, 1=list mode).
+ */
+ uint32_t mode:1;
+ /**
+ * @brief Filter scale.
+ * @note This bit represent the CAN_FS1R register bit associated to this
+ * filter (0=16 bits mode, 1=32 bits mode).
+ */
+ uint32_t scale:1;
+ /**
+ * @brief Filter mode.
+ * @note This bit represent the CAN_FFA1R register bit associated to this
+ * filter, must be set to zero in this version of the driver.
+ */
+ uint32_t assignment:1;
+ /**
+ * @brief Filter register 1 (identifier).
+ */
+ uint32_t register1;
+ /**
+ * @brief Filter register 2 (mask/identifier depending on mode=0/1).
+ */
+ uint32_t register2;
+} CANFilter;
+
+/**
+ * @brief Driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief CAN MCR register initialization data.
+ * @note Some bits in this register are enforced by the driver regardless
+ * their status in this field.
+ */
+ uint32_t mcr;
+ /**
+ * @brief CAN BTR register initialization data.
+ * @note Some bits in this register are enforced by the driver regardless
+ * their status in this field.
+ */
+ uint32_t btr;
+} CANConfig;
+
+/**
+ * @brief Structure representing an CAN driver.
+ */
+struct CANDriver {
+ /**
+ * @brief Driver state.
+ */
+ canstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const CANConfig *config;
+ /**
+ * @brief Transmission threads queue.
+ */
+ threads_queue_t txqueue;
+ /**
+ * @brief Receive threads queue.
+ */
+ threads_queue_t rxqueue;
+#if (CAN_ENFORCE_USE_CALLBACKS == FALSE) || defined(__DOXYGEN__)
+ /**
+ * @brief One or more frames become available.
+ * @note After broadcasting this event it will not be broadcasted again
+ * until the received frames queue has been completely emptied. It
+ * is <b>not</b> broadcasted for each received frame. It is
+ * responsibility of the application to empty the queue by
+ * repeatedly invoking @p canReceive() when listening to this event.
+ * This behavior minimizes the interrupt served by the system
+ * because CAN traffic.
+ * @note The flags associated to the listeners will indicate which
+ * receive mailboxes become non-empty.
+ */
+ event_source_t rxfull_event;
+ /**
+ * @brief One or more transmission mailbox become available.
+ * @note The flags associated to the listeners will indicate which
+ * transmit mailboxes become empty.
+ * @note The upper 16 bits are transmission error flags associated
+ * to the transmit mailboxes.
+ */
+ event_source_t txempty_event;
+ /**
+ * @brief A CAN bus error happened.
+ * @note The flags associated to the listeners will indicate that
+ * receive error(s) have occurred.
+ * @note In this implementation the upper 16 bits are filled with the
+ * unprocessed content of the ESR register.
+ */
+ event_source_t error_event;
+#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__)
+ /**
+ * @brief Entering sleep state event.
+ */
+ event_source_t sleep_event;
+ /**
+ * @brief Exiting sleep state event.
+ */
+ event_source_t wakeup_event;
+#endif /* CAN_USE_SLEEP_MODE */
+#else /* CAN_ENFORCE_USE_CALLBACKS == TRUE */
+ /**
+ * @brief One or more frames become available.
+ * @note After calling this function it will not be called again
+ * until the received frames queue has been completely emptied. It
+ * is <b>not</b> called for each received frame. It is
+ * responsibility of the application to empty the queue by
+ * repeatedly invoking @p chTryReceiveI().
+ * This behavior minimizes the interrupt served by the system
+ * because CAN traffic.
+ */
+ can_callback_t rxfull_cb;
+ /**
+ * @brief One or more transmission mailbox become available.
+ * @note The flags associated to the callback will indicate which
+ * transmit mailboxes become empty.
+ */
+ can_callback_t txempty_cb;
+ /**
+ * @brief A CAN bus error happened.
+ */
+ can_callback_t error_cb;
+#if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__)
+ /**
+ * @brief Exiting sleep state.
+ */
+ can_callback_t wakeup_cb;
+#endif
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the CAN registers.
+ */
+ CAN_TypeDef *can;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_CAN_USE_CAN1 && !defined(__DOXYGEN__)
+extern CANDriver CAND1;
+#endif
+
+#if STM32_CAN_USE_CAN2 && !defined(__DOXYGEN__)
+extern CANDriver CAND2;
+#endif
+
+#if STM32_CAN_USE_CAN3 && !defined(__DOXYGEN__)
+extern CANDriver CAND3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void can_lld_init(void);
+ void can_lld_start(CANDriver *canp);
+ void can_lld_stop(CANDriver *canp);
+ bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox);
+ void can_lld_transmit(CANDriver *canp,
+ canmbx_t mailbox,
+ const CANTxFrame *crfp);
+ bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox);
+ void can_lld_receive(CANDriver *canp,
+ canmbx_t mailbox,
+ CANRxFrame *ctfp);
+ void can_lld_abort(CANDriver *canp,
+ canmbx_t mailbox);
+#if CAN_USE_SLEEP_MODE
+ void can_lld_sleep(CANDriver *canp);
+ void can_lld_wakeup(CANDriver *canp);
+#endif /* CAN_USE_SLEEP_MODE */
+ void canSTM32SetFilters(CANDriver *canp, uint32_t can2sb,
+ uint32_t num, const CANFilter *cfp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_CAN */
+
+#endif /* HAL_CAN_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk new file mode 100644 index 0000000..43936d3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_CRY TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c new file mode 100644 index 0000000..6bb0448 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.c @@ -0,0 +1,1901 @@ +/*
+ 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 CRYPv1/hal_crypto_lld.c
+ * @brief STM32 cryptographic subsystem low level driver source.
+ *
+ * @addtogroup CRYPTO
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define CRYP1_IN_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_CRY_CRYP1_IN_DMA_STREAM, \
+ STM32_CRYP1_IN_DMA_CHN)
+
+#define CRYP1_OUT_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_CRY_CRYP1_OUT_DMA_STREAM, \
+ STM32_CRYP1_OUT_DMA_CHN)
+
+#define HASH1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_CRY_HASH1_DMA_STREAM, \
+ STM32_HASH1_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief CRY1 driver identifier.*/
+#if (STM32_CRY_ENABLED1 == TRUE) || defined(__DOXYGEN__)
+CRYDriver CRYD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if (STM32_CRY_USE_CRYP1 == TRUE) || defined (__DOXYGEN__)
+/**
+ * @brief Setting AES key for encryption.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] algomode algorithm mode field of CR register
+ */
+static inline void cryp_set_key_encrypt(CRYDriver *cryp, uint32_t algomode) {
+ uint32_t cr;
+
+ /* Loading key data.*/
+ CRYP->K0LR = cryp->cryp_k[0];
+ CRYP->K0RR = cryp->cryp_k[1];
+ CRYP->K1LR = cryp->cryp_k[2];
+ CRYP->K1RR = cryp->cryp_k[3];
+ CRYP->K2LR = cryp->cryp_k[4];
+ CRYP->K2RR = cryp->cryp_k[5];
+ CRYP->K3LR = cryp->cryp_k[6];
+ CRYP->K3RR = cryp->cryp_k[7];
+
+ /* Setting up then starting operation.*/
+ cr = CRYP->CR;
+ cr &= ~(CRYP_CR_KEYSIZE_Msk | CRYP_CR_ALGOMODE_Msk | CRYP_CR_ALGODIR_Msk);
+ cr |= cryp->cryp_ksize | algomode | CRYP_CR_CRYPEN;
+ CRYP->CR = cr;
+
+ cryp->cryp_ktype = cryp_key_aes_encrypt;
+}
+
+/**
+ * @brief Setting AES key for decryption.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] algomode algorithm field of CR register
+ */
+static inline void cryp_set_key_decrypt(CRYDriver *cryp, uint32_t algomode) {
+ uint32_t cr;
+
+ /* Loading key data then doing transformation for decrypt.*/
+ cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_KEY);
+ while ((CRYP->CR & CRYP_CR_CRYPEN) != 0U) {
+ }
+
+ /* Setting up then starting operation.*/
+ cr = CRYP->CR;
+ cr &= ~(CRYP_CR_KEYSIZE_Msk | CRYP_CR_ALGOMODE_Msk | CRYP_CR_ALGODIR_Msk);
+ cr |= cryp->cryp_ksize | algomode | CRYP_CR_ALGODIR | CRYP_CR_CRYPEN;
+ CRYP->CR = cr;
+
+ cryp->cryp_ktype = cryp_key_aes_decrypt;
+}
+
+/**
+ * @brief Setting IV.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] iv 128 bits initial vector
+ */
+static inline void cryp_set_iv(CRYDriver *cryp, const uint8_t *iv) {
+
+ (void)cryp;
+
+ CRYP->IV0LR = __REV(__UNALIGNED_UINT32_READ(&iv[0]));
+ CRYP->IV0RR = __REV(__UNALIGNED_UINT32_READ(&iv[4]));
+ CRYP->IV1LR = __REV(__UNALIGNED_UINT32_READ(&iv[8]));
+ CRYP->IV1RR = __REV(__UNALIGNED_UINT32_READ(&iv[12]));
+}
+
+/**
+ * @brief Performs a CRYP operation using DMA.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] size size of both buffers, this number must be a
+ * multiple of 16
+ * @param[in] in input buffer
+ * @param[out] out output buffer
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ */
+static cryerror_t cryp_do_transfer(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out) {
+ uint32_t szw;
+
+ szw = (uint32_t)(size / sizeof (uint32_t));
+#if STM32_CRY_CRYP_SIZE_THRESHOLD > 1
+ if (size >= STM32_CRY_CRYP_SIZE_THRESHOLD)
+#endif
+#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0
+ {
+ /* DMA limitation.*/
+ osalDbgCheck(size < 0x10000U * 4U);
+
+ osalSysLock();
+
+ /* Preparing DMAs.*/
+ dmaStreamSetTransactionSize(cryp->cryp_dma_in, szw);
+ dmaStreamSetTransactionSize(cryp->cryp_dma_out, szw);
+ dmaStreamSetMemory0(cryp->cryp_dma_in, in);
+ dmaStreamSetMemory0(cryp->cryp_dma_out, out);
+ dmaStreamEnable(cryp->cryp_dma_in);
+ dmaStreamEnable(cryp->cryp_dma_out);
+
+ (void) osalThreadSuspendS(&cryp->cryp_tr);
+
+ osalSysUnlock();
+ }
+#endif
+#if STM32_CRY_CRYP_SIZE_THRESHOLD > 1
+ else
+#endif
+#if STM32_CRY_CRYP_SIZE_THRESHOLD != 1
+ {
+ uint32_t nr, nw;
+
+ nr = 0U;
+ nw = 0U;
+ while (nw < szw) {
+
+ if ((CRYP->SR & CRYP_SR_OFNE) != 0U) {
+ __UNALIGNED_UINT32_WRITE(out, CRYP->DOUT);
+ out += 4;
+ nw++;
+ continue; /* Priority to output FIFO.*/
+ }
+
+ if ((nr < szw) && ((CRYP->SR & CRYP_SR_IFNF) != 0U)) {
+ CRYP->DR = __UNALIGNED_UINT32_READ(in);
+ in += 4;
+ nr++;
+ }
+ }
+ }
+#endif
+
+ /* Disabling unit.*/
+ CRYP->CR &= ~CRYP_CR_CRYPEN;
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief CRYP-IN DMA ISR.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void cry_lld_serve_cryp_in_interrupt(CRYDriver *cryp, uint32_t flags) {
+
+ (void)cryp;
+
+ /* DMA errors handling.*/
+#if defined(STM32_CRY_CRYP_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) {
+ STM32_CRY_CRYP_DMA_ERROR_HOOK(cryp);
+ }
+#endif
+}
+
+/**
+ * @brief CRYP-OUT DMA ISR.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void cry_lld_serve_cryp_out_interrupt(CRYDriver *cryp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_CRY_CRYP_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) {
+ STM32_CRY_CRYP_DMA_ERROR_HOOK(cryp);
+ }
+#endif
+
+ /* End buffer interrupt.*/
+ if ((flags & STM32_DMA_ISR_TCIF) != 0U) {
+
+ /* Clearing flags of the other stream too.*/
+ dmaStreamClearInterrupt(cryp->cryp_dma_in);
+
+ /* Resuming waiting thread.*/
+ osalSysLockFromISR();
+ osalThreadResumeI(&cryp->cryp_tr, MSG_OK);
+ osalSysUnlockFromISR();
+ }
+}
+#endif
+
+#if (STM32_CRY_USE_HASH1 == TRUE) || defined (__DOXYGEN__)
+#if (STM32_CRY_HASH_SIZE_THRESHOLD != 0) || defined (__DOXYGEN__)
+/**
+ * @brief HASH DMA ISR.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void cry_lld_serve_hash_interrupt(CRYDriver *cryp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_HASH_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) {
+ STM32_CRY_HASH_DMA_ERROR_HOOK(cryp);
+ }
+#endif
+
+ /* End buffer interrupt.*/
+ if ((flags & STM32_DMA_ISR_TCIF) != 0U) {
+
+ /* Resuming waiting thread.*/
+ osalSysLockFromISR();
+ osalThreadResumeI(&cryp->hash_tr, MSG_OK);
+ osalSysUnlockFromISR();
+ }
+}
+#endif
+#endif
+
+/**
+ * @brief Pushes a series of words into the hash engine.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] n the number of words to be pushed
+ * @param[in] p pointer to the words buffer
+ */
+static void cry_lld_hash_push(CRYDriver *cryp, uint32_t n, const uint32_t *p) {
+
+ (void)cryp; /* Not touched in some cases, needs this.*/
+
+ /* Data is processed in 32kB blocks because DMA size limitations.*/
+ while (n > 0U) {
+ uint32_t chunk = n > 0x8000U ? 0x8000U : n;
+ n -= chunk;
+
+#if STM32_CRY_HASH_SIZE_THRESHOLD > 1
+ if (chunk >= STM32_CRY_HASH_SIZE_THRESHOLD)
+#endif
+#if STM32_CRY_HASH_SIZE_THRESHOLD != 0
+ {
+ /* Setting up transfer.*/
+ dmaStreamSetTransactionSize(cryp->hash_dma, chunk);
+ dmaStreamSetPeripheral(cryp->hash_dma, p);
+ p += chunk;
+
+ osalSysLock();
+
+ /* Enabling DMA channel then HASH engine.*/
+ dmaStreamEnable(cryp->hash_dma);
+
+ /* Waiting for DMA operation completion.*/
+ osalThreadSuspendS(&cryp->hash_tr);
+
+ osalSysUnlock();
+ }
+#endif
+#if STM32_CRY_HASH_SIZE_THRESHOLD > 1
+ else
+#endif
+#if STM32_CRY_HASH_SIZE_THRESHOLD != 1
+ {
+ /* Small chunk, just pushing data without touching DMA.*/
+ do {
+ HASH->DIN = *p++;
+ chunk--;
+ } while (chunk > 0U);
+ }
+#endif
+ }
+
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level crypto driver initialization.
+ *
+ * @notapi
+ */
+void cry_lld_init(void) {
+
+#if STM32_CRY_ENABLED1
+ cryObjectInit(&CRYD1);
+
+#if STM32_CRY_USE_CRYP1
+#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0
+ CRYD1.cryp_tr = NULL;
+ CRYD1.cryp_dma_in = NULL;
+ CRYD1.cryp_dma_out = NULL;
+#endif
+#endif
+
+#if STM32_CRY_USE_HASH1
+#if STM32_CRY_HASH_SIZE_THRESHOLD != 0
+ CRYD1.hash_tr = NULL;
+ CRYD1.hash_dma = NULL;
+#endif /* STM32_CRY_HASH_SIZE_THRESHOLD != 0 */
+#endif /* STM32_CRY_USE_HASH1 */
+
+#endif /* STM32_CRY_ENABLED1 */
+}
+
+/**
+ * @brief Configures and activates the crypto peripheral.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ *
+ * @notapi
+ */
+void cry_lld_start(CRYDriver *cryp) {
+
+ if (cryp->state == CRY_STOP) {
+
+#if STM32_CRY_ENABLED1
+ if (&CRYD1 == cryp) {
+#if STM32_CRY_USE_CRYP1 == TRUE
+#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0
+ /* Allocating DMA channels.*/
+ cryp->cryp_dma_in = dmaStreamAllocI(STM32_CRY_CRYP1_IN_DMA_STREAM,
+ STM32_CRY_CRYP1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)cry_lld_serve_cryp_in_interrupt,
+ (void *)cryp);
+ osalDbgAssert(cryp->cryp_dma_in != NULL, "unable to allocate stream");
+ cryp->cryp_dma_out = dmaStreamAllocI(STM32_CRY_CRYP1_OUT_DMA_STREAM,
+ STM32_CRY_CRYP1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)cry_lld_serve_cryp_out_interrupt,
+ (void *)cryp);
+ osalDbgAssert(cryp->cryp_dma_out != NULL, "unable to allocate stream");
+
+ /* Preparing the DMA channels.*/
+ dmaStreamSetMode(cryp->cryp_dma_in,
+ STM32_DMA_CR_CHSEL(CRYP1_IN_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_CRY_CRYP1_IN_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE);
+ dmaStreamSetMode(cryp->cryp_dma_out,
+ STM32_DMA_CR_CHSEL(CRYP1_OUT_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_CRY_CRYP1_OUT_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
+ STM32_DMA_CR_TCIE);
+ dmaStreamSetPeripheral(cryp->cryp_dma_in, &CRYP->DR);
+ dmaStreamSetPeripheral(cryp->cryp_dma_out, &CRYP->DOUT);
+ dmaStreamSetFIFO(cryp->cryp_dma_in, STM32_DMA_FCR_DMDIS);
+ dmaStreamSetFIFO(cryp->cryp_dma_out, STM32_DMA_FCR_DMDIS);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(cryp->dma_cryp_in, STM32_DMAMUX1_CRYP_IN);
+ dmaSetRequestSource(cryp->dma_cryp_out, STM32_DMAMUX1_CRYP_OUT);
+#endif
+#endif /* STM32_CRY_CRYP_SIZE_THRESHOLD != 0 */
+ rccEnableCRYP(true);
+#endif /* STM32_CRY_USE_CRYP1 == TRUE */
+
+#if STM32_CRY_USE_HASH1 == TRUE
+#if STM32_CRY_HASH_SIZE_THRESHOLD != 0
+ cryp->hash_dma = dmaStreamAllocI(STM32_CRY_HASH1_DMA_STREAM,
+ STM32_CRY_HASH1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)cry_lld_serve_hash_interrupt,
+ (void *)cryp);
+ osalDbgAssert(cryp->hash_dma != NULL, "unable to allocate stream");
+
+ /* Preparing the DMA channel.*/
+ dmaStreamSetMode(cryp->hash_dma,
+ STM32_DMA_CR_CHSEL(HASH1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_CRY_HASH1_DMA_PRIORITY) |
+ STM32_DMA_CR_PINC | STM32_DMA_CR_DIR_M2M |
+ STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
+ STM32_DMA_CR_TCIE);
+ dmaStreamSetMemory0(cryp->hash_dma, &HASH->DIN);
+ dmaStreamSetFIFO(cryp->hash_dma, STM32_DMA_FCR_DMDIS);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(cryp->dma_hash, STM32_DMAMUX1_HASH);
+#endif
+#endif /* STM32_CRY_HASH_SIZE_THRESHOLD != 0 */
+ rccEnableHASH(true);
+#endif /* STM32_CRY_USE_HASH1 == TRUE */
+ }
+#endif
+ }
+
+ /* Resetting trasient key data.*/
+ cryp->cryp_ktype = cryp_key_none;
+ cryp->cryp_ksize = 0U;
+ cryp->cryp_k[0] = 0U;
+ cryp->cryp_k[1] = 0U;
+ cryp->cryp_k[2] = 0U;
+ cryp->cryp_k[3] = 0U;
+ cryp->cryp_k[4] = 0U;
+ cryp->cryp_k[5] = 0U;
+ cryp->cryp_k[6] = 0U;
+ cryp->cryp_k[7] = 0U;
+
+#if STM32_CRY_USE_CRYP1
+ /* CRYP setup.*/
+ CRYP->CR = CRYP_CR_DATATYPE_1;
+ CRYP->DMACR = CRYP_DMACR_DIEN | CRYP_DMACR_DOEN;
+#endif
+
+#if STM32_CRY_USE_HASH1
+ /* HASH setup and enable.*/
+#endif
+}
+
+/**
+ * @brief Deactivates the crypto peripheral.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ *
+ * @notapi
+ */
+void cry_lld_stop(CRYDriver *cryp) {
+
+ if (cryp->state == CRY_READY) {
+
+ /* Resetting CRYP.*/
+ CRYP->CR = 0U;
+ CRYP->DMACR = 0U;
+
+#if STM32_CRY_ENABLED1
+ if (&CRYD1 == cryp) {
+#if STM32_CRY_USE_CRYP1
+#if STM32_CRY_CRYP_SIZE_THRESHOLD != 0
+ dmaStreamFreeI(cryp->cryp_dma_in);
+ dmaStreamFreeI(cryp->cryp_dma_out);
+ cryp->cryp_dma_in = NULL;
+ cryp->cryp_dma_out = NULL;
+#endif
+ rccDisableCRYP();
+#endif
+
+#if STM32_CRY_USE_HASH1
+#if STM32_CRY_HASH_SIZE_THRESHOLD != 0
+ dmaStreamFreeI(cryp->hash_dma);
+ cryp->hash_dma = NULL;
+#endif
+ rccDisableHASH();
+#endif
+ }
+#endif
+ }
+}
+
+#if (CRY_LLD_SUPPORTS_AES == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Initializes the AES transient key.
+ * @note It is the underlying implementation to decide which key sizes are
+ * allowable.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] size key size in bytes
+ * @param[in] keyp pointer to the key data
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported.
+ * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for
+ * the specified algorithm.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_aes_loadkey(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *keyp) {
+
+ /* Fetching key data.*/
+ if (size == (size_t)32) {
+ cryp->cryp_ksize = CRYP_CR_KEYSIZE_1;
+ cryp->cryp_k[0] = __REV(__UNALIGNED_UINT32_READ(&keyp[0]));
+ cryp->cryp_k[1] = __REV(__UNALIGNED_UINT32_READ(&keyp[4]));
+ cryp->cryp_k[2] = __REV(__UNALIGNED_UINT32_READ(&keyp[8]));
+ cryp->cryp_k[3] = __REV(__UNALIGNED_UINT32_READ(&keyp[12]));
+ cryp->cryp_k[4] = __REV(__UNALIGNED_UINT32_READ(&keyp[16]));
+ cryp->cryp_k[5] = __REV(__UNALIGNED_UINT32_READ(&keyp[20]));
+ cryp->cryp_k[6] = __REV(__UNALIGNED_UINT32_READ(&keyp[24]));
+ cryp->cryp_k[7] = __REV(__UNALIGNED_UINT32_READ(&keyp[28]));
+ }
+ else if (size == (size_t)24) {
+ cryp->cryp_ksize = CRYP_CR_KEYSIZE_0;
+ cryp->cryp_k[0] = 0U;
+ cryp->cryp_k[1] = 0U;
+ cryp->cryp_k[2] = __REV(__UNALIGNED_UINT32_READ(&keyp[8]));
+ cryp->cryp_k[3] = __REV(__UNALIGNED_UINT32_READ(&keyp[12]));
+ cryp->cryp_k[4] = __REV(__UNALIGNED_UINT32_READ(&keyp[16]));
+ cryp->cryp_k[5] = __REV(__UNALIGNED_UINT32_READ(&keyp[20]));
+ cryp->cryp_k[6] = __REV(__UNALIGNED_UINT32_READ(&keyp[24]));
+ cryp->cryp_k[7] = __REV(__UNALIGNED_UINT32_READ(&keyp[28]));
+ }
+ else if (size == (size_t)16) {
+ cryp->cryp_ksize = 0U;
+ cryp->cryp_k[0] = 0U;
+ cryp->cryp_k[1] = 0U;
+ cryp->cryp_k[2] = 0U;
+ cryp->cryp_k[3] = 0U;
+ cryp->cryp_k[4] = __REV(__UNALIGNED_UINT32_READ(&keyp[16]));
+ cryp->cryp_k[5] = __REV(__UNALIGNED_UINT32_READ(&keyp[20]));
+ cryp->cryp_k[6] = __REV(__UNALIGNED_UINT32_READ(&keyp[24]));
+ cryp->cryp_k[7] = __REV(__UNALIGNED_UINT32_READ(&keyp[28]));
+ }
+ else {
+ return CRY_ERR_INV_KEY_SIZE;
+ }
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief Encryption of a single block using AES.
+ * @note The implementation of this function must guarantee that it can
+ * be called from any context.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_AES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out) {
+ unsigned i;
+
+ /* Only key zero is supported.*/
+ if (key_id != 0U) {
+ return CRY_ERR_INV_KEY_ID;
+ }
+
+ /* Setting the stored key.*/
+ if (cryp->cryp_ktype != cryp_key_aes_encrypt) {
+ cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB);
+ }
+
+ /* Pushing the AES block in the FIFO, it is assumed to be empty.*/
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[0]);
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[4]);
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[8]);
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[12]);
+
+ /* Reading the result.*/
+ for (i = 0U; i < 4; i++, out += 4) {
+ while ((CRYP->SR & CRYP_SR_OFNE) == 0U) {
+ }
+ __UNALIGNED_UINT32_WRITE(out, CRYP->DOUT);
+ }
+
+ /* Disabling unit.*/
+ CRYP->CR &= ~CRYP_CR_CRYPEN;
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief Decryption of a single block using AES.
+ * @note The implementation of this function must guarantee that it can
+ * be called from any context.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] in buffer containing the input ciphertext
+ * @param[out] out buffer for the output plaintext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_AES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out) {
+ unsigned i;
+
+ /* Only key zero is supported.*/
+ if (key_id != 0U) {
+ return CRY_ERR_INV_KEY_ID;
+ }
+
+ /* Setting the stored key.*/
+ if (cryp->cryp_ktype != cryp_key_aes_decrypt) {
+ cryp_set_key_decrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB);
+ }
+
+ /* Pushing the AES block in the FIFO, it is assumed to be empty.*/
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[0]);
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[4]);
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[8]);
+ CRYP->DR = __UNALIGNED_UINT32_READ(&in[12]);
+
+ /* Reading the result.*/
+ for (i = 0U; i < 4; i++, out += 4) {
+ while ((CRYP->SR & CRYP_SR_OFNE) == 0U) {
+ }
+ __UNALIGNED_UINT32_WRITE(out, CRYP->DOUT);
+ }
+
+ /* Disabling unit.*/
+ CRYP->CR &= ~CRYP_CR_CRYPEN;
+
+ return CRY_NOERROR;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_AES_ECB == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using AES-ECB.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an AES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers, this number must be a
+ * multiple of 16
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_AES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out) {
+
+ /* Only key zero is supported.*/
+ if (key_id != 0U) {
+ return CRY_ERR_INV_KEY_ID;
+ }
+
+ /* Setting the stored key.*/
+ if (cryp->cryp_ktype != cryp_key_aes_encrypt) {
+ cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB);
+ }
+
+ return cryp_do_transfer(cryp, size, in, out);
+}
+
+/**
+ * @brief Decryption operation using AES-ECB.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an AES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers, this number must be a
+ * multiple of 16
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_AES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out) {
+
+ /* Only key zero is supported.*/
+ if (key_id != 0U) {
+ return CRY_ERR_INV_KEY_ID;
+ }
+
+ /* Setting the stored key.*/
+ if (cryp->cryp_ktype != cryp_key_aes_decrypt) {
+ cryp_set_key_decrypt(cryp, CRYP_CR_ALGOMODE_AES_ECB);
+ }
+
+ return cryp_do_transfer(cryp, size, in, out);
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_AES_CBC == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using AES-CBC.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an AES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers, this number must be a
+ * multiple of 16
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @param[in] iv 128 bits initial vector
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_AES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ /* Only key zero is supported.*/
+ if (key_id != 0U) {
+ return CRY_ERR_INV_KEY_ID;
+ }
+
+ /* Setting the stored key and IV.*/
+ cryp_set_iv(cryp, iv);
+ if (cryp->cryp_ktype != cryp_key_aes_encrypt) {
+ cryp_set_key_encrypt(cryp, CRYP_CR_ALGOMODE_AES_CBC);
+ }
+
+ return cryp_do_transfer(cryp, size, in, out);
+}
+
+/**
+ * @brief Decryption operation using AES-CBC.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an AES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers, this number must be a
+ * multiple of 16
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @param[in] iv 128 bits initial vector
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_AES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ /* Only key zero is supported.*/
+ if (key_id != 0U) {
+ return CRY_ERR_INV_KEY_ID;
+ }
+
+ /* Setting the stored key and IV.*/
+ cryp_set_iv(cryp, iv);
+ if (cryp->cryp_ktype != cryp_key_aes_decrypt) {
+ cryp_set_key_decrypt(cryp, CRYP_CR_ALGOMODE_AES_CBC);
+ }
+
+ return cryp_do_transfer(cryp, size, in, out);
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_AES_CFB == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using AES-CFB.
+ * @note This is a stream cipher, there are no size restrictions.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @param[in] iv 128 bits initial vector
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_AES_CFB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+ (void)iv;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Decryption operation using AES-CFB.
+ * @note This is a stream cipher, there are no size restrictions.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @param[in] iv 128 bits initial vector
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_AES_CFB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+ (void)iv;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_AES_CTR == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using AES-CTR.
+ * @note This is a stream cipher, there are no size restrictions.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @param[in] iv 128 bits initial vector + counter, it contains
+ * a 96 bits IV and a 32 bits counter
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_AES_CTR(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+ (void)iv;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Decryption operation using AES-CTR.
+ * @note This is a stream cipher, there are no size restrictions.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of both buffers
+ * @param[in] in buffer containing the input ciphertext
+ * @param[out] out buffer for the output plaintext
+ * @param[in] iv 128 bits initial vector + counter, it contains
+ * a 96 bits IV and a 32 bits counter
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_AES_CTR(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+ (void)iv;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_AES_GCM == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using AES-GCM.
+ * @note This is a stream cipher, there are no size restrictions.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] auth_size size of the data buffer to be authenticated
+ * @param[in] auth_in buffer containing the data to be authenticated
+ * @param[in] text_size size of the text buffer
+ * @param[in] text_in buffer containing the input plaintext
+ * @param[out] text_out buffer for the output ciphertext
+ * @param[in] iv 128 bits input vector
+ * @param[in] tag_size size of the authentication tag, this number
+ * must be between 1 and 16
+ * @param[out] tag_out buffer for the generated authentication tag
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_AES_GCM(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t auth_size,
+ const uint8_t *auth_in,
+ size_t text_size,
+ const uint8_t *text_in,
+ uint8_t *text_out,
+ const uint8_t *iv,
+ size_t tag_size,
+ uint8_t *tag_out) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)auth_size;
+ (void)auth_in;
+ (void)text_size;
+ (void)text_in;
+ (void)text_out;
+ (void)iv;
+ (void)tag_size;
+ (void)tag_out;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Decryption operation using AES-GCM.
+ * @note This is a stream cipher, there are no size restrictions.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] auth_size size of the data buffer to be authenticated
+ * @param[in] auth_in buffer containing the data to be authenticated
+ * @param[in] text_size size of the text buffer
+ * @param[in] text_in buffer containing the input plaintext
+ * @param[out] text_out buffer for the output ciphertext
+ * @param[in] iv 128 bits input vector
+ * @param[in] tag_size size of the authentication tag, this number
+ * must be between 1 and 16
+ * @param[in] tag_in buffer for the generated authentication tag
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_AUTH_FAILED authentication failed
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_AES_GCM(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t auth_size,
+ const uint8_t *auth_in,
+ size_t text_size,
+ const uint8_t *text_in,
+ uint8_t *text_out,
+ const uint8_t *iv,
+ size_t tag_size,
+ const uint8_t *tag_in) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)auth_size;
+ (void)auth_in;
+ (void)text_size;
+ (void)text_in;
+ (void)text_out;
+ (void)iv;
+ (void)tag_size;
+ (void)tag_in;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_DES == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Initializes the DES transient key.
+ * @note It is the underlying implementation to decide which key sizes are
+ * allowable.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] size key size in bytes
+ * @param[in] keyp pointer to the key data
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported.
+ * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for
+ * the specified algorithm.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_des_loadkey(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *keyp) {
+
+ (void)cryp;
+ (void)size;
+ (void)keyp;
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief Encryption of a single block using (T)DES.
+ * @note The implementation of this function must guarantee that it can
+ * be called from any context.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_DES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)in;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Decryption of a single block using (T)DES.
+ * @note The implementation of this function must guarantee that it can
+ * be called from any context.
+ *
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] in buffer containing the input ciphertext
+ * @param[out] out buffer for the output plaintext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_DES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)in;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_DES_ECB == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using (T)DES-ECB.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an DES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of the plaintext buffer, this number must
+ * be a multiple of 8
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_DES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Decryption operation using (T)DES-ECB.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an DES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of the plaintext buffer, this number must
+ * be a multiple of 8
+ * @param[in] in buffer containing the input ciphertext
+ * @param[out] out buffer for the output plaintext
+ * @return T he operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_DES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_DES_CBC == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Encryption operation using (T)DES-CBC.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an DES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of the plaintext buffer, this number must
+ * be a multiple of 8
+ * @param[in] in buffer containing the input plaintext
+ * @param[out] out buffer for the output ciphertext
+ * @param[in] iv 64 bits input vector
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_encrypt_DES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+ (void)iv;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Decryption operation using (T)DES-CBC.
+ * @note The function operates on data buffers whose length is a multiple
+ * of an DES block, this means that padding must be done by the
+ * caller.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] key_id the key to be used for the operation, zero is
+ * the transient key, other values are keys stored
+ * in an unspecified way
+ * @param[in] size size of the plaintext buffer, this number must
+ * be a multiple of 8
+ * @param[in] in buffer containing the input ciphertext
+ * @param[out] out buffer for the output plaintext
+ * @param[in] iv 64 bits input vector
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_INV_KEY_TYPE the selected key is invalid for this operation.
+ * @retval CRY_ERR_INV_KEY_ID if the specified key identifier is invalid
+ * or refers to an empty key slot.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_decrypt_DES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv) {
+
+ (void)cryp;
+ (void)key_id;
+ (void)size;
+ (void)in;
+ (void)out;
+ (void)iv;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Hash initialization using SHA1.
+ * @note Use of this algorithm is not recommended because proven weak.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[out] sha1ctxp pointer to a SHA1 context to be initialized
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA1_init(CRYDriver *cryp, SHA1Context *sha1ctxp) {
+
+ (void)cryp;
+ (void)sha1ctxp;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash update using SHA1.
+ * @note Use of this algorithm is not recommended because proven weak.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] sha1ctxp pointer to a SHA1 context
+ * @param[in] size size of input buffer
+ * @param[in] in buffer containing the input text
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA1_update(CRYDriver *cryp, SHA1Context *sha1ctxp,
+ size_t size, const uint8_t *in) {
+
+ (void)cryp;
+ (void)sha1ctxp;
+ (void)size;
+ (void)in;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash finalization using SHA1.
+ * @note Use of this algorithm is not recommended because proven weak.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] sha1ctxp pointer to a SHA1 context
+ * @param[out] out 160 bits output buffer
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA1_final(CRYDriver *cryp, SHA1Context *sha1ctxp,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)sha1ctxp;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Hash initialization using SHA256.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[out] sha256ctxp pointer to a SHA256 context to be initialized
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp) {
+
+ (void)cryp;
+
+ /* Initializing context structure.*/
+ sha256ctxp->last_data = 0U;
+ sha256ctxp->last_size = 0U;
+
+ /* Initializing operation.*/
+ HASH->CR = /*HASH_CR_MDMAT |*/ HASH_CR_ALGO_1 | HASH_CR_ALGO_0 |
+ HASH_CR_DATATYPE_1 | HASH_CR_INIT;
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief Hash update using SHA256.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] sha256ctxp pointer to a SHA256 context
+ * @param[in] size size of input buffer
+ * @param[in] in buffer containing the input text
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp,
+ size_t size, const uint8_t *in) {
+ const uint32_t *wp = (const uint32_t *)(const void *)in;
+
+ /* This HW is unable to hash blocks that are not a multiple of 4 bytes
+ except for the last block in the stream which is handled in the
+ "final" function.*/
+ if (sha256ctxp->last_size != 0U) {
+ return CRY_ERR_OP_FAILURE;
+ }
+
+ /* Any unaligned data is deferred to the "final" function.*/
+ sha256ctxp->last_size = 8U * (size % sizeof (uint32_t));
+ if (sha256ctxp->last_size > 0U) {
+ sha256ctxp->last_data = wp[size / sizeof (uint32_t)];
+ }
+
+ /* Pushing data.*/
+ cry_lld_hash_push(cryp, (uint32_t)(size / sizeof (uint32_t)), wp);
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief Hash finalization using SHA256.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] sha256ctxp pointer to a SHA256 context
+ * @param[out] out 256 bits output buffer
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA256_final(CRYDriver *cryp, SHA256Context *sha256ctxp,
+ uint8_t *out) {
+ uint32_t digest[8];
+
+ (void)cryp;
+
+ if (sha256ctxp->last_size > 0U) {
+ HASH->DIN = sha256ctxp->last_data;
+ }
+
+ /* Triggering final calculation and wait for result.*/
+ HASH->SR = 0U;
+ HASH->STR = sha256ctxp->last_size;
+ HASH->STR = sha256ctxp->last_size | HASH_STR_DCAL;
+ while ((HASH->SR & HASH_SR_DCIS) == 0U) {
+ }
+
+ /* Reading digest.*/
+ digest[0] = HASH_DIGEST->HR[0];
+ digest[1] = HASH_DIGEST->HR[1];
+ digest[2] = HASH_DIGEST->HR[2];
+ digest[3] = HASH_DIGEST->HR[3];
+ digest[4] = HASH_DIGEST->HR[4];
+ digest[5] = HASH_DIGEST->HR[5];
+ digest[6] = HASH_DIGEST->HR[6];
+ digest[7] = HASH_DIGEST->HR[7];
+ memcpy((void *)out, (const void *)digest, sizeof digest);
+
+ return CRY_NOERROR;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Hash initialization using SHA512.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[out] sha512ctxp pointer to a SHA512 context to be initialized
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA512_init(CRYDriver *cryp, SHA512Context *sha512ctxp) {
+
+ (void)cryp;
+ (void)sha512ctxp;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash update using SHA512.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] sha512ctxp pointer to a SHA512 context
+ * @param[in] size size of input buffer
+ * @param[in] in buffer containing the input text
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA512_update(CRYDriver *cryp, SHA512Context *sha512ctxp,
+ size_t size, const uint8_t *in) {
+
+ (void)cryp;
+ (void)sha512ctxp;
+ (void)size;
+ (void)in;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash finalization using SHA512.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] sha512ctxp pointer to a SHA512 context
+ * @param[out] out 512 bits output buffer
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_SHA512_final(CRYDriver *cryp, SHA512Context *sha512ctxp,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)sha512ctxp;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Initializes the HMAC transient key.
+ * @note It is the underlying implementation to decide which key sizes are
+ * allowable.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] size key size in bytes
+ * @param[in] keyp pointer to the key data
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the algorithm is unsupported.
+ * @retval CRY_ERR_INV_KEY_SIZE if the specified key size is invalid for
+ * the specified algorithm.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_hmac_loadkey(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *keyp) {
+
+ (void)cryp;
+ (void)size;
+ (void)keyp;
+
+ return CRY_NOERROR;
+}
+
+/**
+ * @brief Hash initialization using HMAC_SHA256.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[out] hmacsha256ctxp pointer to a HMAC_SHA256 context to be
+ * initialized
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_HMACSHA256_init(CRYDriver *cryp,
+ HMACSHA256Context *hmacsha256ctxp) {
+
+ (void)cryp;
+ (void)hmacsha256ctxp;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash update using HMAC.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] hmacsha256ctxp pointer to a HMAC_SHA256 context
+ * @param[in] size size of input buffer
+ * @param[in] in buffer containing the input text
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_HMACSHA256_update(CRYDriver *cryp,
+ HMACSHA256Context *hmacsha256ctxp,
+ size_t size,
+ const uint8_t *in) {
+
+ (void)cryp;
+ (void)hmacsha256ctxp;
+ (void)size;
+ (void)in;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash finalization using HMAC.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] hmacsha256ctxp pointer to a HMAC_SHA256 context
+ * @param[out] out 256 bits output buffer
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_HMACSHA256_final(CRYDriver *cryp,
+ HMACSHA256Context *hmacsha256ctxp,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)hmacsha256ctxp;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Hash initialization using HMAC_SHA512.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[out] hmacsha512ctxp pointer to a HMAC_SHA512 context to be
+ * initialized
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_HMACSHA512_init(CRYDriver *cryp,
+ HMACSHA512Context *hmacsha512ctxp) {
+
+ (void)cryp;
+ (void)hmacsha512ctxp;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash update using HMAC.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] hmacsha512ctxp pointer to a HMAC_SHA512 context
+ * @param[in] size size of input buffer
+ * @param[in] in buffer containing the input text
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_HMACSHA512_update(CRYDriver *cryp,
+ HMACSHA512Context *hmacsha512ctxp,
+ size_t size,
+ const uint8_t *in) {
+
+ (void)cryp;
+ (void)hmacsha512ctxp;
+ (void)size;
+ (void)in;
+
+ return CRY_ERR_INV_ALGO;
+}
+
+/**
+ * @brief Hash finalization using HMAC.
+ *
+ * @param[in] cryp pointer to the @p CRYDriver object
+ * @param[in] hmacsha512ctxp pointer to a HMAC_SHA512 context
+ * @param[out] out 512 bits output buffer
+ * @return The operation status.
+ * @retval CRY_NOERROR if the operation succeeded.
+ * @retval CRY_ERR_INV_ALGO if the operation is unsupported on this
+ * device instance.
+ * @retval CRY_ERR_OP_FAILURE if the operation failed, implementation
+ * dependent.
+ *
+ * @notapi
+ */
+cryerror_t cry_lld_HMACSHA512_final(CRYDriver *cryp,
+ HMACSHA512Context *hmacsha512ctxp,
+ uint8_t *out) {
+
+ (void)cryp;
+ (void)hmacsha512ctxp;
+ (void)out;
+
+ return CRY_ERR_INV_ALGO;
+}
+#endif
+
+#endif /* HAL_USE_CRY == TRUE */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h new file mode 100644 index 0000000..257d396 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/CRYPv1/hal_crypto_lld.h @@ -0,0 +1,618 @@ +/*
+ 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 CRYPv1/hal_cry_lld.h
+ * @brief STM32 cryptographic subsystem low level driver header.
+ *
+ * @addtogroup CRYPTO
+ * @{
+ */
+
+#ifndef HAL_CRYPTO_LLD_H
+#define HAL_CRYPTO_LLD_H
+
+#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name STM32 configuration options
+ * @{
+ */
+/**
+ * @brief CRYP1 driver enable switch.
+ * @details If set to @p TRUE the support for CRYP1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_CRY_USE_CRYP1) || defined(__DOXYGEN__)
+#define STM32_CRY_USE_CRYP1 FALSE
+#endif
+
+/**
+ * @brief HASH1 driver enable switch.
+ * @details If set to @p TRUE the support for HASH1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_CRY_USE_HASH1) || defined(__DOXYGEN__)
+#define STM32_CRY_USE_HASH1 FALSE
+#endif
+
+/**
+ * @brief CRYP1 interrupt priority level setting.
+ */
+#if !defined(STM32_CRY_CRYP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CRY_CRYP1_IRQ_PRIORITY 9
+#endif
+
+/**
+ * @brief HASH1 interrupt priority level setting.
+ */
+#if !defined(STM32_CRY_HASH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CRY_HASH1_IRQ_PRIORITY 9
+#endif
+
+/**
+ * @brief HASH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_CRY_CRYP1_OUT_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CRY_CRYP1_OUT_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief HASH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_CRY_HASH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CRY_HASH1_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief Minimum message size (in words) for DMA use.
+ * @note If set to zero then DMA is never used.
+ * @note If set to one then DMA is always used.
+ */
+#if !defined(STM32_CRY_HASH_SIZE_THRESHOLD) || defined(__DOXYGEN__)
+#define STM32_CRY_HASH_SIZE_THRESHOLD 1024
+#endif
+
+/**
+ * @brief Minimum text size (in bytes) for DMA use.
+ * @note If set to zero then DMA is never used.
+ * @note If set to one then DMA is always used.
+ */
+#if !defined(STM32_CRY_CRYP_SIZE_THRESHOLD) || defined(__DOXYGEN__)
+#define STM32_CRY_CRYP_SIZE_THRESHOLD 1024
+#endif
+
+/**
+ * @brief Hash 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_CRY_HASH_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_CRY_HASH_DMA_ERROR_HOOK(cryp) osalSysHalt("DMA failure")
+#endif
+
+/**
+ * @brief CRYP 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_CRY_CRYP_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_CRY_CRYP_DMA_ERROR_HOOK(cryp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if (STM32_CRY_USE_CRYP1 == TRUE) || (STM32_CRY_USE_HASH1 == TRUE) || \
+ defined (__DOXYGEN__)
+#define STM32_CRY_ENABLED1 TRUE
+#else
+#define STM32_CRY_ENABLED1 FALSE
+#endif
+
+#if !defined (STM32_HAS_CRYP1)
+#define STM32_HAS_CRYP1 FALSE
+#endif
+
+#if !defined (STM32_HAS_HASH1)
+#define STM32_HAS_HASH1 FALSE
+#endif
+
+#if STM32_CRY_USE_CRYP1 && !STM32_HAS_CRYP1
+#error "CRYP1 not present in the selected device"
+#endif
+
+#if STM32_CRY_USE_HASH1 && !STM32_HAS_HASH1
+#error "HASH1 not present in the selected device"
+#endif
+
+#if !STM32_CRY_ENABLED1
+#error "CRY driver activated but no CRYP nor HASH peripheral assigned"
+#endif
+
+#if STM32_CRY_USE_HASH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRY_HASH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to HASH1"
+#endif
+
+#if STM32_CRY_USE_CRYP1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_CRY_CRYP1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to CRYP1"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if !defined(STM32_CRY_HASH1_DMA_STREAM)
+#error "HASH1 DMA streams not defined"
+#endif
+
+/* Sanity checks on DMA streams settings in mcuconf.h.*/
+#if STM32_CRY_USE_HASH1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_CRY_HASH1_DMA_STREAM)
+#error "Invalid DMA stream assigned to HASH1"
+#endif
+
+/* Devices without DMAMUX require an additional check.*/
+#if !STM32_DMA_SUPPORTS_DMAMUX
+#if STM32_CRY_USE_CRYP1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_CRY_CRYP1_IN_DMA_STREAM, \
+ STM32_CRYP1_IN_DMA_MSK)
+#error "invalid DMA stream associated to CRYP1_IN"
+#endif
+
+#if STM32_CRY_USE_CRYP1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_CRY_CRYP1_OUT_DMA_STREAM, \
+ STM32_CRYP1_OUT_DMA_MSK)
+#error "invalid DMA stream associated to CRYP1_OUT"
+#endif
+
+#if STM32_CRY_USE_HASH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_CRY_HASH1_DMA_STREAM, STM32_HASH1_DMA_MSK)
+#error "invalid DMA stream associated to HASH1"
+#endif
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* DMA priority check.*/
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_CRYP1_IN_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to CRYP1_IN"
+#endif
+
+/* DMA priority check.*/
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_CRYP1_OUT_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to CRYP1_OUT"
+#endif
+
+/* DMA priority check.*/
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_CRY_HASH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to HASH1"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+#if STM32_CRY_HASH_SIZE_THRESHOLD < 0
+#error "invalid STM32_CRY_HASH_SIZE_THRESHOLD value"
+#endif
+
+/**
+ * @name Driver capability switches
+ * @{
+ */
+#if STM32_CRY_USE_CRYP1 || defined (__DOXYGEN__)
+#define CRY_LLD_SUPPORTS_AES TRUE
+#define CRY_LLD_SUPPORTS_AES_ECB TRUE
+#define CRY_LLD_SUPPORTS_AES_CBC TRUE
+#define CRY_LLD_SUPPORTS_AES_CFB FALSE
+#define CRY_LLD_SUPPORTS_AES_CTR TRUE
+#define CRY_LLD_SUPPORTS_AES_GCM TRUE
+#define CRY_LLD_SUPPORTS_DES TRUE
+#define CRY_LLD_SUPPORTS_DES_ECB TRUE
+#define CRY_LLD_SUPPORTS_DES_CBC TRUE
+#else
+#define CRY_LLD_SUPPORTS_AES FALSE
+#define CRY_LLD_SUPPORTS_AES_ECB FALSE
+#define CRY_LLD_SUPPORTS_AES_CBC FALSE
+#define CRY_LLD_SUPPORTS_AES_CFB FALSE
+#define CRY_LLD_SUPPORTS_AES_CTR FALSE
+#define CRY_LLD_SUPPORTS_AES_GCM FALSE
+#define CRY_LLD_SUPPORTS_DES FALSE
+#define CRY_LLD_SUPPORTS_DES_ECB FALSE
+#define CRY_LLD_SUPPORTS_DES_CBC FALSE
+#endif
+#if STM32_CRY_USE_HASH1 || defined (__DOXYGEN__)
+#define CRY_LLD_SUPPORTS_SHA1 FALSE
+#define CRY_LLD_SUPPORTS_SHA256 TRUE
+#define CRY_LLD_SUPPORTS_SHA512 FALSE
+#define CRY_LLD_SUPPORTS_HMAC_SHA256 TRUE
+#define CRY_LLD_SUPPORTS_HMAC_SHA512 FALSE
+#else
+#define CRY_LLD_SUPPORTS_SHA1 FALSE
+#define CRY_LLD_SUPPORTS_SHA256 FALSE
+#define CRY_LLD_SUPPORTS_SHA512 FALSE
+#define CRY_LLD_SUPPORTS_HMAC_SHA256 FALSE
+#define CRY_LLD_SUPPORTS_HMAC_SHA512 FALSE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief CRY key identifier type.
+ */
+typedef uint32_t crykey_t;
+
+/**
+ * @brief Type of a structure representing an CRY driver.
+ */
+typedef struct CRYDriver CRYDriver;
+
+/**
+ * @brief Type of key stored in CRYP.
+ */
+typedef enum {
+ cryp_key_none = 0,
+ cryp_key_des = 1,
+ cryp_key_tdes = 2,
+ cryp_key_aes_encrypt = 3,
+ cryp_key_aes_decrypt = 4
+} cryp_ktype_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ uint32_t dummy;
+} CRYConfig;
+
+/**
+ * @brief Structure representing an CRY driver.
+ */
+struct CRYDriver {
+ /**
+ * @brief Driver state.
+ */
+ crystate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const CRYConfig *config;
+#if defined(CRY_DRIVER_EXT_FIELDS)
+ CRY_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+#if (STM32_CRY_USE_CRYP1 == TRUE) || defined (__DOXYGEN__)
+ /**
+ * @brief Type of the key currently stored in CRYP.
+ */
+ cryp_ktype_t cryp_ktype;
+ /**
+ * @brief Key size setup value for CR register.
+ */
+ uint32_t cryp_ksize;
+ /**
+ * @brief Transient key data.
+ */
+ uint32_t cryp_k[8];
+#if (STM32_CRY_CRYP_SIZE_THRESHOLD != 0) || defined (__DOXYGEN__)
+ /**
+ * @brief Thread reference for CRYP operations.
+ */
+ thread_reference_t cryp_tr;
+ /**
+ * @brief CRYP IN DMA stream.
+ */
+ const stm32_dma_stream_t *cryp_dma_in;
+ /**
+ * @brief CRYP OUT DMA stream.
+ */
+ const stm32_dma_stream_t *cryp_dma_out;
+#endif /* STM32_CRY_CRYP_SIZE_THRESHOLD != 0 */
+#endif /* STM32_CRY_USE_CRYP1 == TRUE */
+#if (STM32_CRY_USE_HASH1 == TRUE) || defined (__DOXYGEN__)
+#if (STM32_CRY_HASH_SIZE_THRESHOLD != 0) || defined (__DOXYGEN__)
+ /**
+ * @brief Thread reference for hash operations.
+ */
+ thread_reference_t hash_tr;
+ /**
+ * @brief Hash DMA stream.
+ */
+ const stm32_dma_stream_t *hash_dma;
+#endif /* STM32_CRY_HASH_SIZE_THRESHOLD != 0 */
+#endif /* STM32_CRY_USE_HASH1 == TRUE */
+};
+
+#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a SHA1 context.
+ */
+typedef struct {
+ uint32_t dummy;
+} SHA1Context;
+#endif
+
+#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a SHA256 context.
+ */
+typedef struct {
+ /**
+ * @brief Last data to be hashed on finalization.
+ */
+ uint32_t last_data;
+ /**
+ * @brief Size, in bits, of the last data.
+ */
+ uint32_t last_size;
+} SHA256Context;
+#endif
+
+#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a SHA512 context.
+ */
+typedef struct {
+ uint32_t dummy;
+} SHA512Context;
+#endif
+
+#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a HMAC_SHA256 context.
+ */
+typedef struct {
+ uint32_t dummy;
+} HMACSHA256Context;
+#endif
+
+#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a HMAC_SHA512 context.
+ */
+typedef struct {
+ uint32_t dummy;
+} HMACSHA512Context;
+#endif
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if (STM32_CRY_ENABLED1 == TRUE) && !defined(__DOXYGEN__)
+extern CRYDriver CRYD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void cry_lld_init(void);
+ void cry_lld_start(CRYDriver *cryp);
+ void cry_lld_stop(CRYDriver *cryp);
+#if (CRY_LLD_SUPPORTS_AES == TRUE) || \
+ (CRY_LLD_SUPPORTS_AES_ECB == TRUE) || \
+ (CRY_LLD_SUPPORTS_AES_CBC == TRUE) || \
+ (CRY_LLD_SUPPORTS_AES_CFB == TRUE) || \
+ (CRY_LLD_SUPPORTS_AES_CTR == TRUE) || \
+ (CRY_LLD_SUPPORTS_AES_GCM == TRUE) || \
+ defined(__DOXYGEN__)
+ cryerror_t cry_lld_aes_loadkey(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *keyp);
+#endif
+#if (CRY_LLD_SUPPORTS_AES == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_AES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out);
+ cryerror_t cry_lld_decrypt_AES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_AES_ECB == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_AES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out);
+ cryerror_t cry_lld_decrypt_AES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_AES_CBC == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_AES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+ cryerror_t cry_lld_decrypt_AES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+#endif
+#if (CRY_LLD_SUPPORTS_AES_CFB == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_AES_CFB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+ cryerror_t cry_lld_decrypt_AES_CFB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+#endif
+#if (CRY_LLD_SUPPORTS_AES_CTR == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_AES_CTR(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+ cryerror_t cry_lld_decrypt_AES_CTR(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+#endif
+#if (CRY_LLD_SUPPORTS_AES_GCM == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_AES_GCM(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t auth_size,
+ const uint8_t *auth_in,
+ size_t text_size,
+ const uint8_t *text_in,
+ uint8_t *text_out,
+ const uint8_t *iv,
+ size_t tag_size,
+ uint8_t *tag_out);
+ cryerror_t cry_lld_decrypt_AES_GCM(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t auth_size,
+ const uint8_t *auth_in,
+ size_t text_size,
+ const uint8_t *text_in,
+ uint8_t *text_out,
+ const uint8_t *iv,
+ size_t tag_size,
+ const uint8_t *tag_in);
+#endif
+#if (CRY_LLD_SUPPORTS_DES == TRUE) || \
+ (CRY_LLD_SUPPORTS_DES_ECB == TRUE) || \
+ (CRY_LLD_SUPPORTS_DES_CBC == TRUE) || \
+ defined(__DOXYGEN__)
+ cryerror_t cry_lld_des_loadkey(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *keyp);
+#endif
+#if (CRY_LLD_SUPPORTS_DES == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_DES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out);
+ cryerror_t cry_lld_decrypt_DES(CRYDriver *cryp,
+ crykey_t key_id,
+ const uint8_t *in,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_DES_ECB == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_DES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out);
+ cryerror_t cry_lld_decrypt_DES_ECB(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_DES_CBC == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_encrypt_DES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+ cryerror_t cry_lld_decrypt_DES_CBC(CRYDriver *cryp,
+ crykey_t key_id,
+ size_t size,
+ const uint8_t *in,
+ uint8_t *out,
+ const uint8_t *iv);
+#endif
+#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_SHA1_init(CRYDriver *cryp, SHA1Context *sha1ctxp);
+ cryerror_t cry_lld_SHA1_update(CRYDriver *cryp, SHA1Context *sha1ctxp,
+ size_t size, const uint8_t *in);
+ cryerror_t cry_lld_SHA1_final(CRYDriver *cryp, SHA1Context *sha1ctxp,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp);
+ cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp,
+ size_t size, const uint8_t *in);
+ cryerror_t cry_lld_SHA256_final(CRYDriver *cryp, SHA256Context *sha256ctxp,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_SHA512_init(CRYDriver *cryp, SHA512Context *sha512ctxp);
+ cryerror_t cry_lld_SHA512_update(CRYDriver *cryp, SHA512Context *sha512ctxp,
+ size_t size, const uint8_t *in);
+ cryerror_t cry_lld_SHA512_final(CRYDriver *cryp, SHA512Context *sha512ctxp,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || \
+ (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || \
+ defined(__DOXYGEN__)
+ cryerror_t cry_lld_hmac_loadkey(CRYDriver *cryp,
+ size_t size,
+ const uint8_t *keyp);
+#endif
+#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_HMACSHA256_init(CRYDriver *cryp,
+ HMACSHA256Context *hmacsha256ctxp);
+ cryerror_t cry_lld_HMACSHA256_update(CRYDriver *cryp,
+ HMACSHA256Context *hmacsha256ctxp,
+ size_t size, const uint8_t *in);
+ cryerror_t cry_lld_HMACSHA256_final(CRYDriver *cryp,
+ HMACSHA256Context *hmacsha256ctxp,
+ uint8_t *out);
+#endif
+#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__)
+ cryerror_t cry_lld_HMACSHA512_init(CRYDriver *cryp,
+ HMACSHA512Context *hmacsha512ctxp);
+ cryerror_t cry_lld_HMACSHA512_update(CRYDriver *cryp,
+ HMACSHA512Context *hmacsha512ctxp,
+ size_t size, const uint8_t *in);
+ cryerror_t cry_lld_HMACSHA512_final(CRYDriver *cryp,
+ HMACSHA512Context *hmacsha512ctxp,
+ uint8_t *out);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_CRY == TRUE */
+
+#endif /* HAL_CRYPTO_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk new file mode 100644 index 0000000..da95148 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c new file mode 100644 index 0000000..1b32a82 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c @@ -0,0 +1,769 @@ +/*
+ 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 DACv1/hal_dac_lld.c
+ * @brief STM32 DAC subsystem low level driver source.
+ *
+ * @addtogroup DAC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_DAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* Because ST headers naming inconsistencies.*/
+#if !defined(DAC1)
+#define DAC1 DAC
+#endif
+
+#define DAC1_CH1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH1_DMA_STREAM, \
+ STM32_DAC1_CH1_DMA_CHN)
+
+#define DAC1_CH2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH2_DMA_STREAM, \
+ STM32_DAC1_CH2_DMA_CHN)
+
+#define DAC2_CH1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH1_DMA_STREAM, \
+ STM32_DAC2_CH1_DMA_CHN)
+
+#define DAC2_CH2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH2_DMA_STREAM, \
+ STM32_DAC2_CH2_DMA_CHN)
+
+#define DAC3_CH1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH1_DMA_STREAM, \
+ STM32_DAC3_CH1_DMA_CHN)
+
+#define DAC3_CH2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH2_DMA_STREAM, \
+ STM32_DAC3_CH2_DMA_CHN)
+
+#define DAC4_CH1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH1_DMA_STREAM, \
+ STM32_DAC4_CH1_DMA_CHN)
+
+#define DAC4_CH2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH2_DMA_STREAM, \
+ STM32_DAC4_CH2_DMA_CHN)
+
+#define CHANNEL_DATA_OFFSET 3U
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief DAC1 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__)
+DACDriver DACD1;
+#endif
+
+/** @brief DAC1 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD2;
+#endif
+
+/** @brief DAC2 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__)
+DACDriver DACD3;
+#endif
+
+/** @brief DAC2 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD4;
+#endif
+
+/** @brief DAC3 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC3_CH1 || defined(__DOXYGEN__)
+DACDriver DACD5;
+#endif
+
+/** @brief DAC3 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD6;
+#endif
+
+/** @brief DAC4 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC4_CH1 || defined(__DOXYGEN__)
+DACDriver DACD7;
+#endif
+
+/** @brief DAC4 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+#if STM32_DAC_USE_DAC1_CH1 == TRUE
+static const dacparams_t dac1_ch1_params = {
+ .dac = DAC1,
+ .dataoffset = 0U,
+ .regshift = 0U,
+ .regmask = 0xFFFF0000U,
+ .dmastream = STM32_DAC_DAC1_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC1_CH1,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC1_CH1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC1_CH1_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC1_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 == TRUE
+static const dacparams_t dac1_ch2_params = {
+ .dac = DAC1,
+ .dataoffset = CHANNEL_DATA_OFFSET,
+ .regshift = 16U,
+ .regmask = 0x0000FFFFU,
+ .dmastream = STM32_DAC_DAC1_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC1_CH2,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC1_CH2_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC1_CH2_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 == TRUE
+static const dacparams_t dac2_ch1_params = {
+ .dac = DAC2,
+ .dataoffset = 0U,
+ .regshift = 0U,
+ .regmask = 0xFFFF0000U,
+ .dmastream = STM32_DAC_DAC2_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC2_CH1,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC2_CH1_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC2_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 == TRUE
+static const dacparams_t dac2_ch2_params = {
+ .dac = DAC2,
+ .dataoffset = CHANNEL_DATA_OFFSET,
+ .regshift = 16U,
+ .regmask = 0x0000FFFFU,
+ .dmastream = STM32_DAC_DAC2_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC2_CH2,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC2_CH2_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC2_CH2_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 == TRUE
+static const dacparams_t dac3_ch1_params = {
+ .dac = DAC3,
+ .dataoffset = 0U,
+ .regshift = 0U,
+ .regmask = 0xFFFF0000U,
+ .dmastream = STM32_DAC_DAC3_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC3_CH1,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC3_CH1_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC3_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 == TRUE
+static const dacparams_t dac3_ch2_params = {
+ .dac = DAC3,
+ .dataoffset = CHANNEL_DATA_OFFSET,
+ .regshift = 16U,
+ .regmask = 0x0000FFFFU,
+ .dmastream = STM32_DAC_DAC3_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC3_CH2,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH2_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC3_CH2_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC3_CH2_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 == TRUE
+static const dacparams_t dac4_ch1_params = {
+ .dac = DAC4,
+ .dataoffset = 0U,
+ .regshift = 0U,
+ .regmask = 0xFFFF0000U,
+ .dmastream = STM32_DAC_DAC4_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC4_CH1,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC4_CH1_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC4_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 == TRUE
+static const dacparams_t dac4_ch2_params = {
+ .dac = DAC4,
+ .dataoffset = CHANNEL_DATA_OFFSET,
+ .regshift = 16U,
+ .regmask = 0x0000FFFFU,
+ .dmastream = STM32_DAC_DAC4_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC4_CH2,
+#endif
+ .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH2_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_DAC_DAC4_CH2_DMA_PRIORITY) |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE,
+ .dmairqprio = STM32_DAC_DAC4_CH2_IRQ_PRIORITY
+};
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Shared end/half-of-tx service routine.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) {
+
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ /* DMA errors handling.*/
+ //dac_lld_stop_conversion(dacp);
+ _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE);
+ }
+ else {
+ if ((flags & STM32_DMA_ISR_HTIF) != 0) {
+ /* Half transfer processing.*/
+ _dac_isr_half_code(dacp);
+ }
+ if ((flags & STM32_DMA_ISR_TCIF) != 0) {
+ /* Transfer complete processing.*/
+ _dac_isr_full_code(dacp);
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level DAC driver initialization.
+ *
+ * @notapi
+ */
+void dac_lld_init(void) {
+
+#if STM32_DAC_USE_DAC1_CH1
+ dacObjectInit(&DACD1);
+ DACD1.params = &dac1_ch1_params;
+ DACD1.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2
+ dacObjectInit(&DACD2);
+ DACD2.params = &dac1_ch2_params;
+ DACD2.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1
+ dacObjectInit(&DACD3);
+ DACD3.params = &dac2_ch1_params;
+ DACD3.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2
+ dacObjectInit(&DACD4);
+ DACD4.params = &dac2_ch2_params;
+ DACD4.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1
+ dacObjectInit(&DACD5);
+ DACD5.params = &dac3_ch1_params;
+ DACD5.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2
+ dacObjectInit(&DACD6);
+ DACD6.params = &dac3_ch2_params;
+ DACD6.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1
+ dacObjectInit(&DACD7);
+ DACD7.params = &dac4_ch1_params;
+ DACD7.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2
+ dacObjectInit(&DACD8);
+ DACD8.params = &dac4_ch2_params;
+ DACD8.dma = NULL;
+#endif
+}
+
+/**
+ * @brief Configures and activates the DAC peripheral.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_start(DACDriver *dacp) {
+
+ /* If the driver is in DAC_STOP state then a full initialization is
+ required.*/
+ if (dacp->state == DAC_STOP) {
+ dacchannel_t channel = 0;
+
+ /* Enabling the clock source.*/
+#if STM32_DAC_USE_DAC1_CH1
+ if (&DACD1 == dacp) {
+ rccEnableDAC1(true);
+ }
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2
+ if (&DACD2 == dacp) {
+ rccEnableDAC1(true);
+ channel = 1;
+ }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1
+ if (&DACD3 == dacp) {
+ rccEnableDAC2(true);
+ }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2
+ if (&DACD4 == dacp) {
+ rccEnableDAC2(true);
+ channel = 1;
+ }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1
+ if (&DACD5 == dacp) {
+ rccEnableDAC3(true);
+ }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2
+ if (&DACD6 == dacp) {
+ rccEnableDAC3(true);
+ channel = 1;
+ }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1
+ if (&DACD7 == dacp) {
+ rccEnableDAC4(true);
+ }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2
+ if (&DACD8 == dacp) {
+ rccEnableDAC4(true);
+ channel = 1;
+ }
+#endif
+
+ /* Enabling DAC in SW triggering mode initially, initializing data to
+ zero.*/
+#if STM32_DAC_DUAL_MODE == FALSE
+ {
+ uint32_t cr;
+
+ cr = dacp->params->dac->CR;
+ cr &= dacp->params->regmask;
+ cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+ dacp->params->dac->CR = cr;
+ dac_lld_put_channel(dacp, channel, dacp->config->init);
+ }
+#else
+ if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) {
+ dacp->params->dac->CR = DAC_CR_EN2 | (dacp->config->cr << 16) | DAC_CR_EN1 | dacp->config->cr;
+ dac_lld_put_channel(dacp, 1U, dacp->config->init);
+ }
+ else {
+ dacp->params->dac->CR = DAC_CR_EN1 | dacp->config->cr;
+ }
+ dac_lld_put_channel(dacp, channel, dacp->config->init);
+#endif
+ }
+}
+
+/**
+ * @brief Deactivates the DAC peripheral.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_stop(DACDriver *dacp) {
+
+ /* If in ready state then disables the DAC clock.*/
+ if (dacp->state == DAC_READY) {
+
+ /* Disabling DAC.*/
+ dacp->params->dac->CR &= dacp->params->regmask;
+
+#if STM32_DAC_USE_DAC1_CH1
+ if (&DACD1 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+ rccDisableDAC1();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2
+ if (&DACD2 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+ rccDisableDAC1();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1
+ if (&DACD3 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+ rccDisableDAC2();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2
+ if (&DACD4 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+ rccDisableDAC2();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1
+ if (&DACD5 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+ rccDisableDAC3();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2
+ if (&DACD6 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+ rccDisableDAC3();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1
+ if (&DACD7 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+ rccDisableDAC4();
+ }
+ }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2
+ if (&DACD8 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+ rccDisableDAC4();
+ }
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Outputs a value directly on a DAC channel.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ * @param[in] channel DAC channel number
+ * @param[in] sample value to be output
+ *
+ * @api
+ */
+void dac_lld_put_channel(DACDriver *dacp,
+ dacchannel_t channel,
+ dacsample_t sample) {
+
+ switch (dacp->config->datamode) {
+ case DAC_DHRM_12BIT_RIGHT:
+#if STM32_DAC_DUAL_MODE
+ case DAC_DHRM_12BIT_RIGHT_DUAL:
+#endif
+ if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+ dacp->params->dac->DHR12R1 = (uint32_t)sample;
+#else
+ *(&dacp->params->dac->DHR12R1 + dacp->params->dataoffset) = (uint32_t)sample;
+#endif
+ }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \
+ STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+ else {
+ dacp->params->dac->DHR12R2 = (uint32_t)sample;
+ }
+#endif
+ break;
+ case DAC_DHRM_12BIT_LEFT:
+#if STM32_DAC_DUAL_MODE
+ case DAC_DHRM_12BIT_LEFT_DUAL:
+#endif
+ if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+ dacp->params->dac->DHR12L1 = (uint32_t)sample;
+#else
+ *(&dacp->params->dac->DHR12L1 + dacp->params->dataoffset) = (uint32_t)sample;
+#endif
+ }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \
+ STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+ else {
+ dacp->params->dac->DHR12L2 = (uint32_t)sample;
+ }
+#endif
+ break;
+ case DAC_DHRM_8BIT_RIGHT:
+#if STM32_DAC_DUAL_MODE
+ case DAC_DHRM_8BIT_RIGHT_DUAL:
+#endif
+ if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+ dacp->params->dac->DHR8R1 = (uint32_t)sample;
+#else
+ *(&dacp->params->dac->DHR8R1 + dacp->params->dataoffset) = (uint32_t)sample;
+#endif
+ }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \
+ STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+ else {
+ dacp->params->dac->DHR8R2 = (uint32_t)sample;
+ }
+#endif
+ break;
+ default:
+ osalDbgAssert(false, "unexpected DAC mode");
+ break;
+ }
+}
+
+/**
+ * @brief Starts a DAC conversion.
+ * @details Starts an asynchronous conversion operation.
+ * @note In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the
+ * callback are wrong because two samples are packed in a single
+ * dacsample_t element. This will not be corrected, do not rely
+ * on those parameters.
+ * @note In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated
+ * as a single 16 bits sample and packed into a single dacsample_t
+ * element. The num_channels must be set to one in the group
+ * conversion configuration structure.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_start_conversion(DACDriver *dacp) {
+ uint32_t n, cr, dmamode;
+
+ /* Number of DMA operations per buffer.*/
+ n = dacp->depth * dacp->grpp->num_channels;
+
+ /* Allocating the DMA channel.*/
+ dacp->dma = dmaStreamAllocI(dacp->params->dmastream,
+ dacp->params->dmairqprio,
+ (stm32_dmaisr_t)dac_lld_serve_tx_interrupt,
+ (void *)dacp);
+ osalDbgAssert(dacp->dma != NULL, "unable to allocate stream");
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(dacp->dma, dacp->params->peripheral);
+#endif
+
+ /* DMA settings depend on the chosen DAC mode.*/
+ switch (dacp->config->datamode) {
+ /* Sets the DAC data register */
+ case DAC_DHRM_12BIT_RIGHT:
+ osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+
+ dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12R1 +
+ dacp->params->dataoffset);
+ dmamode = dacp->params->dmamode |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ break;
+// case DAC_DHRM_12BIT_LEFT:
+// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12L1 +
+// dacp->params->dataoffset);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+// break;
+// case DAC_DHRM_8BIT_RIGHT:
+// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8R1 +
+// dacp->params->dataoffset);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+//
+// /* In this mode the size of the buffer is halved because two samples
+// packed in a single dacsample_t element.*/
+// n = (n + 1) / 2;
+// break;
+//#if STM32_DAC_DUAL_MODE == TRUE
+// case DAC_DHRM_12BIT_RIGHT_DUAL:
+// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12RD);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+// n /= 2;
+// break;
+// case DAC_DHRM_12BIT_LEFT_DUAL:
+// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12LD);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+// n /= 2;
+// break;
+// case DAC_DHRM_8BIT_RIGHT_DUAL:
+// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8RD);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+// n /= 2;
+// break;
+//#endif
+ default:
+ osalDbgAssert(false, "unexpected DAC mode");
+ return;
+ }
+
+ dmaStreamSetMemory0(dacp->dma, dacp->samples);
+ dmaStreamSetTransactionSize(dacp->dma, n);
+ dmaStreamSetMode(dacp->dma, dmamode |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
+ STM32_DMA_CR_HTIE | STM32_DMA_CR_TCIE);
+ dmaStreamEnable(dacp->dma);
+
+ /* DAC configuration.*/
+ cr = dacp->params->dac->CR;
+
+#if STM32_DAC_DUAL_MODE == FALSE
+ cr &= dacp->params->regmask;
+ cr |= (DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+#else
+ cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr
+ | (dacp->grpp->trigger << DAC_CR_TSEL2_Pos) | DAC_CR_TEN2 | DAC_CR_EN2 | (dacp->config->cr << 16);
+#endif
+
+ dacp->params->dac->CR = cr;
+}
+
+/**
+ * @brief Stops an ongoing conversion.
+ * @details This function stops the currently ongoing conversion and returns
+ * the driver in the @p DAC_READY state. If there was no conversion
+ * being processed then the function does nothing.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @iclass
+ */
+void dac_lld_stop_conversion(DACDriver *dacp) {
+ uint32_t cr;
+
+ /* DMA channel disabled and released.*/
+ dmaStreamDisable(dacp->dma);
+ dmaStreamFreeI(dacp->dma);
+ dacp->dma = NULL;
+
+ cr = dacp->params->dac->CR;
+
+#if STM32_DAC_DUAL_MODE == FALSE
+ cr &= dacp->params->regmask;
+ cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+#else
+ if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) {
+ cr = DAC_CR_EN2 | (dacp->config->cr << 16) |
+ DAC_CR_EN1 | dacp->config->cr;
+ }
+ else {
+ cr = DAC_CR_EN1 | dacp->config->cr;
+ }
+#endif
+
+ dacp->params->dac->CR = cr;
+}
+
+#endif /* HAL_USE_DAC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak new file mode 100644 index 0000000..02aefc8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.c.bak @@ -0,0 +1,735 @@ +/*
+ 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 DACv1/hal_dac_lld.c
+ * @brief STM32 DAC subsystem low level driver source.
+ *
+ * @addtogroup DAC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_DAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* Because ST headers naming inconsistencies.*/
+#if !defined(DAC1)
+#define DAC1 DAC
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief DAC1 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__)
+DACDriver DACD1;
+#endif
+
+///** @brief DAC1 CH2 driver identifier.*/
+//#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+//DACDriver DACD2;
+//#endif
+//
+///** @brief DAC2 CH1 driver identifier.*/
+//#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__)
+//DACDriver DACD3;
+//#endif
+//
+///** @brief DAC2 CH2 driver identifier.*/
+//#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+//DACDriver DACD4;
+//#endif
+//
+///** @brief DAC3 CH1 driver identifier.*/
+//#if STM32_DAC_USE_DAC3_CH1 || defined(__DOXYGEN__)
+//DACDriver DACD5;
+//#endif
+//
+///** @brief DAC3 CH2 driver identifier.*/
+//#if (STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+//DACDriver DACD6;
+//#endif
+//
+///** @brief DAC4 CH1 driver identifier.*/
+//#if STM32_DAC_USE_DAC4_CH1 || defined(__DOXYGEN__)
+//DACDriver DACD7;
+//#endif
+//
+///** @brief DAC4 CH2 driver identifier.*/
+//#if (STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+//DACDriver DACD8;
+//#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+#if STM32_DAC_USE_DAC1_CH1 == TRUE
+static const dacparams_t dac1_ch1_params = {
+ .dac = DAC1,
+ .dataoffset = 0U,
+ .regshift = 0U,
+ .regmask = 0xFFFF0000U,
+ .dmastream = STM32_DAC_DAC1_CH1_BDMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+ .peripheral = STM32_DMAMUX1_DAC1_CH1,
+#endif
+ .dmamode = STM32_BDMA_CR_MSIZE_HWORD | STM32_BDMA_CR_PSIZE_WORD |
+ STM32_BDMA_CR_PL(STM32_DAC_DAC1_CH1_DMA_PRIORITY) |
+ STM32_BDMA_CR_DIR_M2P |
+ STM32_BDMA_CR_MINC | STM32_BDMA_CR_TCIE | STM32_BDMA_CR_HTIE |
+ STM32_BDMA_CR_TEIE | STM32_BDMA_CR_CIRC,
+ .dmairqprio = STM32_DAC_DAC1_CH1_IRQ_PRIORITY
+};
+#endif
+
+//#if STM32_DAC_USE_DAC1_CH2 == TRUE
+//static const dacparams_t dac1_ch2_params = {
+// .dac = DAC1,
+// .dataoffset = CHANNEL_DATA_OFFSET,
+// .regshift = 16U,
+// .regmask = 0x0000FFFFU,
+// .dmastream = STM32_DAC_DAC1_CH2_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC1_CH2,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC1_CH2_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC1_CH2_IRQ_PRIORITY
+//};
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH1 == TRUE
+//static const dacparams_t dac2_ch1_params = {
+// .dac = DAC2,
+// .dataoffset = 0U,
+// .regshift = 0U,
+// .regmask = 0xFFFF0000U,
+// .dmastream = STM32_DAC_DAC2_CH1_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC2_CH1,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC2_CH1_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC2_CH1_IRQ_PRIORITY
+//};
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH2 == TRUE
+//static const dacparams_t dac2_ch2_params = {
+// .dac = DAC2,
+// .dataoffset = CHANNEL_DATA_OFFSET,
+// .regshift = 16U,
+// .regmask = 0x0000FFFFU,
+// .dmastream = STM32_DAC_DAC2_CH2_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC2_CH2,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC2_CH2_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC2_CH2_IRQ_PRIORITY
+//};
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH1 == TRUE
+//static const dacparams_t dac3_ch1_params = {
+// .dac = DAC3,
+// .dataoffset = 0U,
+// .regshift = 0U,
+// .regmask = 0xFFFF0000U,
+// .dmastream = STM32_DAC_DAC3_CH1_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC3_CH1,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH1_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC3_CH1_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC3_CH1_IRQ_PRIORITY
+//};
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH2 == TRUE
+//static const dacparams_t dac3_ch2_params = {
+// .dac = DAC3,
+// .dataoffset = CHANNEL_DATA_OFFSET,
+// .regshift = 16U,
+// .regmask = 0x0000FFFFU,
+// .dmastream = STM32_DAC_DAC3_CH2_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC3_CH2,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC3_CH2_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC3_CH2_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC3_CH2_IRQ_PRIORITY
+//};
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH1 == TRUE
+//static const dacparams_t dac4_ch1_params = {
+// .dac = DAC4,
+// .dataoffset = 0U,
+// .regshift = 0U,
+// .regmask = 0xFFFF0000U,
+// .dmastream = STM32_DAC_DAC4_CH1_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC4_CH1,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH1_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC4_CH1_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC4_CH1_IRQ_PRIORITY
+//};
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH2 == TRUE
+//static const dacparams_t dac4_ch2_params = {
+// .dac = DAC4,
+// .dataoffset = CHANNEL_DATA_OFFSET,
+// .regshift = 16U,
+// .regmask = 0x0000FFFFU,
+// .dmastream = STM32_DAC_DAC4_CH2_DMA_STREAM,
+//#if STM32_DMA_SUPPORTS_DMAMUX
+// .peripheral = STM32_DMAMUX1_DAC4_CH2,
+//#endif
+// .dmamode = STM32_DMA_CR_CHSEL(DAC4_CH2_DMA_CHANNEL) |
+// STM32_DMA_CR_PL(STM32_DAC_DAC4_CH2_DMA_PRIORITY) |
+// STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+// STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+// STM32_DMA_CR_TCIE,
+// .dmairqprio = STM32_DAC_DAC4_CH2_IRQ_PRIORITY
+//};
+//#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Shared end/half-of-tx service routine.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) {
+ if ((flags & STM32_BDMA_ISR_TEIF) != 0) {
+ /* DMA errors handling.*/
+ dac_lld_stop_conversion(dacp);
+ _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE);
+ }
+ else {
+ if ((flags & STM32_BDMA_ISR_HTIF) != 0) {
+ /* Half transfer processing.*/
+ _dac_isr_half_code(dacp);
+ }
+ if ((flags & STM32_BDMA_ISR_TCIF) != 0) {
+ /* Transfer complete processing.*/
+ _dac_isr_full_code(dacp);
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level DAC driver initialization.
+ *
+ * @notapi
+ */
+void dac_lld_init(void) {
+
+#if STM32_DAC_USE_DAC1_CH1
+ dacObjectInit(&DACD1);
+ DACD1.params = &dac1_ch1_params;
+ DACD1.bdma = NULL;
+#endif
+
+//#if STM32_DAC_USE_DAC1_CH2
+// dacObjectInit(&DACD2);
+// DACD2.params = &dac1_ch2_params;
+// DACD2.dma = NULL;
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH1
+// dacObjectInit(&DACD3);
+// DACD3.params = &dac2_ch1_params;
+// DACD3.dma = NULL;
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH2
+// dacObjectInit(&DACD4);
+// DACD4.params = &dac2_ch2_params;
+// DACD4.dma = NULL;
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH1
+// dacObjectInit(&DACD5);
+// DACD5.params = &dac3_ch1_params;
+// DACD5.dma = NULL;
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH2
+// dacObjectInit(&DACD6);
+// DACD6.params = &dac3_ch2_params;
+// DACD6.dma = NULL;
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH1
+// dacObjectInit(&DACD7);
+// DACD7.params = &dac4_ch1_params;
+// DACD7.dma = NULL;
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH2
+// dacObjectInit(&DACD8);
+// DACD8.params = &dac4_ch2_params;
+// DACD8.dma = NULL;
+//#endif
+}
+
+/**
+ * @brief Configures and activates the DAC peripheral.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_start(DACDriver *dacp) {
+
+ /* If the driver is in DAC_STOP state then a full initialization is
+ required.*/
+ if (dacp->state == DAC_STOP) {
+ dacchannel_t channel = 0;
+
+ /* Enabling the clock source.*/
+#if STM32_DAC_USE_DAC1_CH1
+ if (&DACD1 == dacp) {
+ rccEnableDAC1(true);
+ }
+#endif
+
+//#if STM32_DAC_USE_DAC1_CH2
+// if (&DACD2 == dacp) {
+// rccEnableDAC1(true);
+// channel = 1;
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH1
+// if (&DACD3 == dacp) {
+// rccEnableDAC2(true);
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH2
+// if (&DACD4 == dacp) {
+// rccEnableDAC2(true);
+// channel = 1;
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH1
+// if (&DACD5 == dacp) {
+// rccEnableDAC3(true);
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH2
+// if (&DACD6 == dacp) {
+// rccEnableDAC3(true);
+// channel = 1;
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH1
+// if (&DACD7 == dacp) {
+// rccEnableDAC4(true);
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH2
+// if (&DACD8 == dacp) {
+// rccEnableDAC4(true);
+// channel = 1;
+// }
+//#endif
+
+ /* Enabling DAC in SW triggering mode initially, initializing data to
+ zero.*/
+#if STM32_DAC_DUAL_MODE == FALSE
+ {
+ uint32_t cr;
+
+ cr = dacp->params->dac->CR;
+ cr &= dacp->params->regmask;
+ cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+ dacp->params->dac->MCR = 2;
+ dacp->params->dac->CR = cr;
+ dac_lld_put_channel(dacp, channel, dacp->config->init);
+ }
+#else
+ if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) {
+ dacp->params->dac->CR = DAC_CR_EN2 | (dacp->config->cr << 16) | DAC_CR_EN1 | dacp->config->cr;
+ dac_lld_put_channel(dacp, 1U, dacp->config->init);
+ }
+ else {
+ dacp->params->dac->CR = DAC_CR_EN1 | dacp->config->cr;
+ }
+ dac_lld_put_channel(dacp, channel, dacp->config->init);
+#endif
+ }
+}
+
+/**
+ * @brief Deactivates the DAC peripheral.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_stop(DACDriver *dacp) {
+
+ /* If in ready state then disables the DAC clock.*/
+ if (dacp->state == DAC_READY) {
+
+ /* Disabling DAC.*/
+ dacp->params->dac->CR &= dacp->params->regmask;
+
+#if STM32_DAC_USE_DAC1_CH1
+ if (&DACD1 == dacp) {
+ if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+ rccDisableDAC1();
+ }
+ }
+#endif
+
+//#if STM32_DAC_USE_DAC1_CH2
+// if (&DACD2 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+// rccDisableDAC1();
+// }
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH1
+// if (&DACD3 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+// rccDisableDAC2();
+// }
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC2_CH2
+// if (&DACD4 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+// rccDisableDAC2();
+// }
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH1
+// if (&DACD5 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+// rccDisableDAC3();
+// }
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC3_CH2
+// if (&DACD6 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+// rccDisableDAC3();
+// }
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH1
+// if (&DACD7 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+// rccDisableDAC4();
+// }
+// }
+//#endif
+//
+//#if STM32_DAC_USE_DAC4_CH2
+// if (&DACD8 == dacp) {
+// if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+// rccDisableDAC4();
+// }
+// }
+//#endif
+ }
+}
+
+/**
+ * @brief Outputs a value directly on a DAC channel.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ * @param[in] channel DAC channel number
+ * @param[in] sample value to be output
+ *
+ * @api
+ */
+void dac_lld_put_channel(DACDriver *dacp,
+ dacchannel_t channel,
+ dacsample_t sample) {
+
+ switch (dacp->config->datamode) {
+ case DAC_DHRM_12BIT_RIGHT:
+#if STM32_DAC_DUAL_MODE
+ case DAC_DHRM_12BIT_RIGHT_DUAL:
+#endif
+ if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+ dacp->params->dac->DHR12R1 = (uint32_t)sample;
+#else
+ *(&dacp->params->dac->DHR12R1 + dacp->params->dataoffset) = (uint32_t)sample;
+#endif
+ }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \
+ STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+ else {
+ dacp->params->dac->DHR12R2 = (uint32_t)sample;
+ }
+#endif
+ break;
+ case DAC_DHRM_12BIT_LEFT:
+#if STM32_DAC_DUAL_MODE
+ case DAC_DHRM_12BIT_LEFT_DUAL:
+#endif
+ if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+ dacp->params->dac->DHR12L1 = (uint32_t)sample;
+#else
+ *(&dacp->params->dac->DHR12L1 + dacp->params->dataoffset) = (uint32_t)sample;
+#endif
+ }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \
+ STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+ else {
+ dacp->params->dac->DHR12L2 = (uint32_t)sample;
+ }
+#endif
+ break;
+ case DAC_DHRM_8BIT_RIGHT:
+#if STM32_DAC_DUAL_MODE
+ case DAC_DHRM_8BIT_RIGHT_DUAL:
+#endif
+ if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+ dacp->params->dac->DHR8R1 = (uint32_t)sample;
+#else
+ *(&dacp->params->dac->DHR8R1 + dacp->params->dataoffset) = (uint32_t)sample;
+#endif
+ }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 || \
+ STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+ else {
+ dacp->params->dac->DHR8R2 = (uint32_t)sample;
+ }
+#endif
+ break;
+ default:
+ osalDbgAssert(false, "unexpected DAC mode");
+ break;
+ }
+}
+
+/**
+ * @brief Starts a DAC conversion.
+ * @details Starts an asynchronous conversion operation.
+ * @note In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the
+ * callback are wrong because two samples are packed in a single
+ * dacsample_t element. This will not be corrected, do not rely
+ * on those parameters.
+ * @note In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated
+ * as a single 16 bits sample and packed into a single dacsample_t
+ * element. The num_channels must be set to one in the group
+ * conversion configuration structure.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_start_conversion(DACDriver *dacp) {
+ uint32_t n, cr, dmamode;
+
+ /* Number of DMA operations per buffer.*/
+ n = dacp->depth * dacp->grpp->num_channels;
+
+ /* Allocating the DMA channel.*/
+ dacp->bdma = bdmaStreamAllocI(dacp->params->dmastream,
+ dacp->params->dmairqprio,
+ (stm32_dmaisr_t)dac_lld_serve_tx_interrupt,
+ (void *)dacp);
+ osalDbgAssert(dacp->bdma != NULL, "unable to allocate stream");
+#if STM32_DMA_SUPPORTS_DMAMUX
+ bdmaSetRequestSource(dacp->bdma, dacp->params->peripheral);
+#endif
+
+ /* DMA settings depend on the chosen DAC mode.*/
+ switch (dacp->config->datamode) {
+ /* Sets the DAC data register */
+ case DAC_DHRM_12BIT_RIGHT:
+ osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+
+ bdmaStreamSetPeripheral(dacp->bdma, &dacp->params->dac->DHR12R1 +
+ dacp->params->dataoffset);
+ dmamode = dacp->params->dmamode |
+ STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_HWORD;
+ break;
+// case DAC_DHRM_12BIT_LEFT:
+// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12L1 +
+// dacp->params->dataoffset);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+// break;
+// case DAC_DHRM_8BIT_RIGHT:
+// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8R1 +
+// dacp->params->dataoffset);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+//
+// /* In this mode the size of the buffer is halved because two samples
+// packed in a single dacsample_t element.*/
+// n = (n + 1) / 2;
+// break;
+//#if STM32_DAC_DUAL_MODE == TRUE
+// case DAC_DHRM_12BIT_RIGHT_DUAL:
+// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12RD);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+// n /= 2;
+// break;
+// case DAC_DHRM_12BIT_LEFT_DUAL:
+// osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12LD);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+// n /= 2;
+// break;
+// case DAC_DHRM_8BIT_RIGHT_DUAL:
+// osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+//
+// dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8RD);
+// dmamode = dacp->params->dmamode |
+// STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+// n /= 2;
+// break;
+//#endif
+ default:
+ osalDbgAssert(false, "unexpected DAC mode");
+ return;
+ }
+
+ bdmaStreamSetMemory(dacp->bdma, dacp->samples);
+ bdmaStreamSetTransactionSize(dacp->bdma, n);
+ bdmaStreamSetMode(dacp->bdma, dmamode |
+ STM32_BDMA_CR_TEIE |
+ STM32_BDMA_CR_HTIE | STM32_BDMA_CR_TCIE);
+ bdmaStreamEnable(dacp->bdma);
+
+ /* DAC configuration.*/
+ cr = dacp->params->dac->CR;
+
+#if STM32_DAC_DUAL_MODE == FALSE
+ cr &= dacp->params->regmask;
+ cr |= (DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+#else
+ cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr
+ | (dacp->grpp->trigger << DAC_CR_TSEL2_Pos) | DAC_CR_TEN2 | DAC_CR_EN2 | (dacp->config->cr << 16);
+#endif
+
+ dacp->params->dac->CR = cr;
+}
+
+/**
+ * @brief Stops an ongoing conversion.
+ * @details This function stops the currently ongoing conversion and returns
+ * the driver in the @p DAC_READY state. If there was no conversion
+ * being processed then the function does nothing.
+ *
+ * @param[in] dacp pointer to the @p DACDriver object
+ *
+ * @iclass
+ */
+void dac_lld_stop_conversion(DACDriver *dacp) {
+ uint32_t cr;
+
+ /* DMA channel disabled and released.*/
+ bdmaStreamDisable(dacp->bdma);
+ bdmaStreamFreeI(dacp->bdma);
+ dacp->bdma = NULL;
+
+ cr = dacp->params->dac->CR;
+
+#if STM32_DAC_DUAL_MODE == FALSE
+ cr &= dacp->params->regmask;
+ cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+#else
+ if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) ||
+ (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) {
+ cr = DAC_CR_EN2 | (dacp->config->cr << 16) |
+ DAC_CR_EN1 | dacp->config->cr;
+ }
+ else {
+ cr = DAC_CR_EN1 | dacp->config->cr;
+ }
+#endif
+
+ dacp->params->dac->CR = cr;
+}
+
+#endif /* HAL_USE_DAC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h new file mode 100644 index 0000000..09550fa --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h @@ -0,0 +1,662 @@ +/*
+ 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 DACv1/hal_dac_lld.h
+ * @brief STM32 DAC subsystem low level driver header.
+ *
+ * @addtogroup DAC
+ * @{
+ */
+
+#ifndef HAL_DAC_LLD_H
+#define HAL_DAC_LLD_H
+
+#if HAL_USE_DAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name DAC trigger modes
+ * @{
+ */
+#define DAC_TRG_MASK 7U
+#define DAC_TRG(n) (n)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Enables the DAC dual mode.
+ * @note In dual mode DAC second channels cannot be accessed individually.
+ */
+#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+#define STM32_DAC_DUAL_MODE FALSE
+#endif
+
+/**
+ * @brief DAC1 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC1 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC1_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC1 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC1 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC1_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC2 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC2 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC2_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC2 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC2 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC2_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC3 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC3 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC3_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC3_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC3 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC3 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC3_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC3_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC4 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC4 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC4_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC4_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC4 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC4 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC4_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC4_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC1 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC1 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC2 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC2 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC3 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC3 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC4 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC4 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC1 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC1 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC2 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC2 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC3 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC3_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC3 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC3_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC4 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC4_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC4 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC4_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH2_DMA_PRIORITY 2
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Handling missing registry keys.*/
+#if !defined(STM32_HAS_DAC1_CH1)
+#define STM32_HAS_DAC1_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC1_CH2)
+#define STM32_HAS_DAC1_CH2 FALSE
+#endif
+#if !defined(STM32_HAS_DAC2_CH1)
+#define STM32_HAS_DAC2_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC2_CH2)
+#define STM32_HAS_DAC2_CH2 FALSE
+#endif
+#if !defined(STM32_HAS_DAC3_CH1)
+#define STM32_HAS_DAC3_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC3_CH2)
+#define STM32_HAS_DAC3_CH2 FALSE
+#endif
+#if !defined(STM32_HAS_DAC4_CH1)
+#define STM32_HAS_DAC4_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC4_CH2)
+#define STM32_HAS_DAC4_CH2 FALSE
+#endif
+
+#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1
+#error "DAC1 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2
+#error "DAC1 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1
+#error "DAC2 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2
+#error "DAC2 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !STM32_HAS_DAC3_CH1
+#error "DAC3 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !STM32_HAS_DAC3_CH2
+#error "DAC3 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !STM32_HAS_DAC4_CH1
+#error "DAC4 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !STM32_HAS_DAC4_CH2
+#error "DAC4 CH2 not present in the selected device"
+#endif
+
+#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2 || \
+ STM32_DAC_USE_DAC3_CH2 || STM32_DAC_USE_DAC4_CH2) && STM32_DAC_DUAL_MODE
+#error "DACx CH2 cannot be used independently in dual mode"
+#endif
+
+#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 && \
+ !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 && \
+ !STM32_DAC_USE_DAC3_CH1 && !STM32_DAC_USE_DAC3_CH2 && \
+ !STM32_DAC_USE_DAC4_CH1 && !STM32_DAC_USE_DAC4_CH2
+#error "DAC driver activated but no DAC peripheral assigned"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC3 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC3 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC4 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC4 CH2"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC_DAC1_CH1_DMA_STREAM)
+#error "DAC1 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC_DAC1_CH2_DMA_STREAM)
+#error "DAC1 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC_DAC2_CH1_DMA_STREAM)
+#error "DAC2 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC_DAC2_CH2_DMA_STREAM)
+#error "DAC2 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !defined(STM32_DAC_DAC3_CH1_DMA_STREAM)
+#error "DAC3 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !defined(STM32_DAC_DAC3_CH2_DMA_STREAM)
+#error "DAC3 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !defined(STM32_DAC_DAC4_CH1_DMA_STREAM)
+#error "DAC4 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !defined(STM32_DAC_DAC4_CH2_DMA_STREAM)
+#error "DAC4 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DMA_SUPPORTS_DMAMUX
+
+#else /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* Check on the validity of the assigned DMA streams.*/
+#if STM32_DAC_USE_DAC1_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH1_DMA_STREAM, STM32_DAC3_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH2_DMA_STREAM, STM32_DAC3_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH1_DMA_STREAM, STM32_DAC4_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH2_DMA_STREAM, STM32_DAC4_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH2"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+#endif /* STM32_ADVANCED_DMA */
+
+#if STM32_DAC_USE_DAC1_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC3 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC3 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC4 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC4 CH2"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/**
+ * @brief Max DAC channels.
+ */
+#if STM32_DAC_DUAL_MODE == FALSE
+#define DAC_MAX_CHANNELS 2
+#else
+#define DAC_MAX_CHANNELS 1
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a DAC channel index.
+ */
+typedef uint32_t dacchannel_t;
+
+/**
+ * @brief Type representing a DAC sample.
+ */
+typedef uint16_t dacsample_t;
+
+/**
+ * @brief DAC channel parameters type.
+ */
+typedef struct {
+ /**
+ * @brief Pointer to the DAC registers block.
+ */
+ DAC_TypeDef *dac;
+ /**
+ * @brief DAC data registers offset.
+ */
+ uint32_t dataoffset;
+ /**
+ * @brief DAC CR register bit offset.
+ */
+ uint32_t regshift;
+ /**
+ * @brief DAC CR register mask.
+ */
+ uint32_t regmask;
+ /**
+ * @brief Associated DMA stream.
+ */
+ uint32_t dmastream;
+ /**
+ * @brief Mode bits for the DMA.
+ */
+ uint32_t dmamode;
+ /**
+ * @brief DMA channel IRQ priority.
+ */
+ uint32_t dmairqprio;
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief DMAMUX peripheral selector.
+ */
+ uint32_t peripheral;
+#endif
+} dacparams_t;
+
+/**
+ * @brief Possible DAC failure causes.
+ * @note Error codes are architecture dependent and should not relied
+ * upon.
+ */
+typedef enum {
+ DAC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */
+ DAC_ERR_UNDERFLOW = 1 /**< DAC overflow condition. */
+} dacerror_t;
+
+/**
+ * @brief Samples alignment and size mode.
+ */
+typedef enum {
+ DAC_DHRM_12BIT_RIGHT = 0,
+ DAC_DHRM_12BIT_LEFT = 1,
+ DAC_DHRM_8BIT_RIGHT = 2,
+#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+ DAC_DHRM_12BIT_RIGHT_DUAL = 3,
+ DAC_DHRM_12BIT_LEFT_DUAL = 4,
+ DAC_DHRM_8BIT_RIGHT_DUAL = 5
+#endif
+} dacdhrmode_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the DAC driver structure.
+ */
+#define dac_lld_driver_fields \
+ /* DAC channel parameters.*/ \
+ const dacparams_t *params; \
+ /* Associated DMA.*/ \
+ const stm32_dma_stream_t *dma
+
+/**
+ * @brief Low level fields of the DAC configuration structure.
+ */
+#define dac_lld_config_fields \
+ /* Initial output on DAC channels.*/ \
+ dacsample_t init; \
+ /* DAC data holding register mode.*/ \
+ dacdhrmode_t datamode; \
+ /* DAC control register lower 16 bits.*/ \
+ uint32_t cr
+
+/**
+ * @brief Low level fields of the DAC group configuration structure.
+ */
+#define dac_lld_conversion_group_fields \
+ /* DAC initialization data. This field contains the (not shifted) value \
+ to be put into the TSEL field of the DAC CR register during \
+ initialization. All other fields are handled internally.*/ \
+ uint32_t trigger
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD1;
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD2;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD3;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD4;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD5;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD6;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD7;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void dac_lld_init(void);
+ void dac_lld_start(DACDriver *dacp);
+ void dac_lld_stop(DACDriver *dacp);
+ void dac_lld_put_channel(DACDriver *dacp,
+ dacchannel_t channel,
+ dacsample_t sample);
+ void dac_lld_start_conversion(DACDriver *dacp);
+ void dac_lld_stop_conversion(DACDriver *dacp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_DAC */
+
+#endif /* HAL_DAC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak new file mode 100644 index 0000000..1e369ca --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DACv1/hal_dac_lld.h.bak @@ -0,0 +1,662 @@ +/*
+ 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 DACv1/hal_dac_lld.h
+ * @brief STM32 DAC subsystem low level driver header.
+ *
+ * @addtogroup DAC
+ * @{
+ */
+
+#ifndef HAL_DAC_LLD_H
+#define HAL_DAC_LLD_H
+
+#if HAL_USE_DAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name DAC trigger modes
+ * @{
+ */
+#define DAC_TRG_MASK 7U
+#define DAC_TRG(n) (n)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Enables the DAC dual mode.
+ * @note In dual mode DAC second channels cannot be accessed individually.
+ */
+#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+#define STM32_DAC_DUAL_MODE FALSE
+#endif
+
+/**
+ * @brief DAC1 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC1 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC1_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC1 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC1 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC1_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC2 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC2 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC2_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC2 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC2 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC2_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC3 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC3 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC3_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC3_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC3 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC3 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC3_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC3_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC4 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC4 channel 1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC4_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC4_CH1 FALSE
+#endif
+
+/**
+ * @brief DAC4 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC4 channel 2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC4_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC4_CH2 FALSE
+#endif
+
+/**
+ * @brief DAC1 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC1 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC2 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC2 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC3 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC3 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC4 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC4 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DAC1 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC1 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC2 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC2 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC3 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC3_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC3 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC3_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH2_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC4 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC4_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH1_DMA_PRIORITY 2
+#endif
+
+/**
+ * @brief DAC4 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC4_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH2_DMA_PRIORITY 2
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Handling missing registry keys.*/
+#if !defined(STM32_HAS_DAC1_CH1)
+#define STM32_HAS_DAC1_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC1_CH2)
+#define STM32_HAS_DAC1_CH2 FALSE
+#endif
+#if !defined(STM32_HAS_DAC2_CH1)
+#define STM32_HAS_DAC2_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC2_CH2)
+#define STM32_HAS_DAC2_CH2 FALSE
+#endif
+#if !defined(STM32_HAS_DAC3_CH1)
+#define STM32_HAS_DAC3_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC3_CH2)
+#define STM32_HAS_DAC3_CH2 FALSE
+#endif
+#if !defined(STM32_HAS_DAC4_CH1)
+#define STM32_HAS_DAC4_CH1 FALSE
+#endif
+#if !defined(STM32_HAS_DAC4_CH2)
+#define STM32_HAS_DAC4_CH2 FALSE
+#endif
+
+#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1
+#error "DAC1 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2
+#error "DAC1 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1
+#error "DAC2 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2
+#error "DAC2 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !STM32_HAS_DAC3_CH1
+#error "DAC3 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !STM32_HAS_DAC3_CH2
+#error "DAC3 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !STM32_HAS_DAC4_CH1
+#error "DAC4 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !STM32_HAS_DAC4_CH2
+#error "DAC4 CH2 not present in the selected device"
+#endif
+
+#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2 || \
+ STM32_DAC_USE_DAC3_CH2 || STM32_DAC_USE_DAC4_CH2) && STM32_DAC_DUAL_MODE
+#error "DACx CH2 cannot be used independently in dual mode"
+#endif
+
+#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 && \
+ !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 && \
+ !STM32_DAC_USE_DAC3_CH1 && !STM32_DAC_USE_DAC3_CH2 && \
+ !STM32_DAC_USE_DAC4_CH1 && !STM32_DAC_USE_DAC4_CH2
+#error "DAC driver activated but no DAC peripheral assigned"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC3 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC3 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC4 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC4 CH2"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC_DAC1_CH1_BDMA_STREAM)
+#error "DAC1 CH1 BDMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC_DAC1_CH2_DMA_STREAM)
+#error "DAC1 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC_DAC2_CH1_DMA_STREAM)
+#error "DAC2 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC_DAC2_CH2_DMA_STREAM)
+#error "DAC2 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !defined(STM32_DAC_DAC3_CH1_DMA_STREAM)
+#error "DAC3 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !defined(STM32_DAC_DAC3_CH2_DMA_STREAM)
+#error "DAC3 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !defined(STM32_DAC_DAC4_CH1_DMA_STREAM)
+#error "DAC4 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !defined(STM32_DAC_DAC4_CH2_DMA_STREAM)
+#error "DAC4 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DMA_SUPPORTS_DMAMUX
+
+#else /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* Check on the validity of the assigned DMA streams.*/
+#if STM32_DAC_USE_DAC1_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH1_DMA_STREAM, STM32_DAC3_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH2_DMA_STREAM, STM32_DAC3_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH1_DMA_STREAM, STM32_DAC4_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH2_DMA_STREAM, STM32_DAC4_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH2"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+#endif /* STM32_ADVANCED_DMA */
+
+#if STM32_DAC_USE_DAC1_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC3 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC3 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC4 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC4 CH2"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/**
+ * @brief Max DAC channels.
+ */
+#if STM32_DAC_DUAL_MODE == FALSE
+#define DAC_MAX_CHANNELS 2
+#else
+#define DAC_MAX_CHANNELS 1
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a DAC channel index.
+ */
+typedef uint32_t dacchannel_t;
+
+/**
+ * @brief Type representing a DAC sample.
+ */
+typedef uint16_t dacsample_t;
+
+/**
+ * @brief DAC channel parameters type.
+ */
+typedef struct {
+ /**
+ * @brief Pointer to the DAC registers block.
+ */
+ DAC_TypeDef *dac;
+ /**
+ * @brief DAC data registers offset.
+ */
+ uint32_t dataoffset;
+ /**
+ * @brief DAC CR register bit offset.
+ */
+ uint32_t regshift;
+ /**
+ * @brief DAC CR register mask.
+ */
+ uint32_t regmask;
+ /**
+ * @brief Associated DMA stream.
+ */
+ uint32_t dmastream;
+ /**
+ * @brief Mode bits for the DMA.
+ */
+ uint32_t dmamode;
+ /**
+ * @brief DMA channel IRQ priority.
+ */
+ uint32_t dmairqprio;
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief DMAMUX peripheral selector.
+ */
+ uint32_t peripheral;
+#endif
+} dacparams_t;
+
+/**
+ * @brief Possible DAC failure causes.
+ * @note Error codes are architecture dependent and should not relied
+ * upon.
+ */
+typedef enum {
+ DAC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */
+ DAC_ERR_UNDERFLOW = 1 /**< DAC overflow condition. */
+} dacerror_t;
+
+/**
+ * @brief Samples alignment and size mode.
+ */
+typedef enum {
+ DAC_DHRM_12BIT_RIGHT = 0,
+ DAC_DHRM_12BIT_LEFT = 1,
+ DAC_DHRM_8BIT_RIGHT = 2,
+#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+ DAC_DHRM_12BIT_RIGHT_DUAL = 3,
+ DAC_DHRM_12BIT_LEFT_DUAL = 4,
+ DAC_DHRM_8BIT_RIGHT_DUAL = 5
+#endif
+} dacdhrmode_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the DAC driver structure.
+ */
+#define dac_lld_driver_fields \
+ /* DAC channel parameters.*/ \
+ const dacparams_t *params; \
+ /* Associated DMA.*/ \
+ const stm32_bdma_stream_t *bdma
+
+/**
+ * @brief Low level fields of the DAC configuration structure.
+ */
+#define dac_lld_config_fields \
+ /* Initial output on DAC channels.*/ \
+ dacsample_t init; \
+ /* DAC data holding register mode.*/ \
+ dacdhrmode_t datamode; \
+ /* DAC control register lower 16 bits.*/ \
+ uint32_t cr
+
+/**
+ * @brief Low level fields of the DAC group configuration structure.
+ */
+#define dac_lld_conversion_group_fields \
+ /* DAC initialization data. This field contains the (not shifted) value \
+ to be put into the TSEL field of the DAC CR register during \
+ initialization. All other fields are handled internally.*/ \
+ uint32_t trigger
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD1;
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD2;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD3;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD4;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD5;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD6;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD7;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void dac_lld_init(void);
+ void dac_lld_start(DACDriver *dacp);
+ void dac_lld_stop(DACDriver *dacp);
+ void dac_lld_put_channel(DACDriver *dacp,
+ dacchannel_t channel,
+ dacsample_t sample);
+ void dac_lld_start_conversion(DACDriver *dacp);
+ void dac_lld_stop_conversion(DACDriver *dacp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_DAC */
+
+#endif /* HAL_DAC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk new file mode 100644 index 0000000..6080cec --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt new file mode 100644 index 0000000..dc46638 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/notes.txt @@ -0,0 +1,26 @@ +STM32 DMAv1 driver.
+
+Driver capability:
+
+- The driver supports the STM32 traditional DMA controller in the following
+ configurations: 5ch, 7ch, 7ch+5ch, 7ch+7ch.
+- Support for automatic the channel selection through the CSELR register.
+- For devices without CSELR register it is possible to select channels but
+ the SYSCFG CFGR register is not configured, the user has to configure it
+ before starting the DMA driver.
+- The driver supports shared ISR handlers with a quirk: the IRQ priority is
+ established by the first allocated channel among the channels sharing the
+ ISR.
+
+The file registry must export:
+
+STM32_ADVANCED_DMA - TRUE not used by the DMA drivers but other
+ drivers use it to enable checks on DMA
+ channels. Probably will be removed in the
+ future.
+STM32_DMA_SUPPORTS_CSELR - TRUE if the DMA have a CSELR register.
+STM32_DMA_SUPPORTS_DMAMUX - TRUE if the DMA is riven by a DMAMUX.
+STM32_DMAn_NUM_CHANNELS - Number of channels in DMAs "n" (1..2).
+STM32_DMAn_CHx_HANDLER - Vector name for IRQ "x" (1..7). If the macro
+ is not exported then the ISR is not declared.
+STM32_DMAn_CHx_NUMBER - Vector number for IRQ "x" (1..7).
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c new file mode 100644 index 0000000..141b4ff --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c @@ -0,0 +1,816 @@ +/*
+ 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 DMAv1/stm32_dma.c
+ * @brief DMA helper driver code.
+ *
+ * @addtogroup STM32_DMA
+ * @details DMA sharing helper driver. In the STM32 the DMA streams are a
+ * shared resource, this driver allows to allocate and free DMA
+ * streams at runtime in order to allow all the other device
+ * drivers to coordinate the access to the resource.
+ * @note The DMA ISR handlers are all declared into this module because
+ * sharing, the various device drivers can associate a callback to
+ * ISRs when allocating streams.
+ * @{
+ */
+
+#include "hal.h"
+
+/* The following macro is only defined if some driver requiring DMA services
+ has been enabled.*/
+#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/**
+ * @brief Mask of the DMA1 streams in @p dma_streams_mask.
+ */
+#define STM32_DMA1_STREAMS_MASK ((1U << STM32_DMA1_NUM_CHANNELS) - 1U)
+
+/**
+ * @brief Mask of the DMA2 streams in @p dma_streams_mask.
+ */
+#define STM32_DMA2_STREAMS_MASK (((1U << STM32_DMA2_NUM_CHANNELS) - \
+ 1U) << STM32_DMA1_NUM_CHANNELS)
+
+#if STM32_DMA_SUPPORTS_CSELR == TRUE
+
+#if defined(DMA1_CSELR)
+#define __DMA1_CSELR &DMA1_CSELR->CSELR
+#else
+#define __DMA1_CSELR &DMA1->CSELR
+#endif
+
+#if defined(DMA2_CSELR)
+#define __DMA2_CSELR &DMA2_CSELR->CSELR
+#else
+#define __DMA2_CSELR &DMA2->CSELR
+#endif
+
+#define DMA1_CH1_VARIANT __DMA1_CSELR
+#define DMA1_CH2_VARIANT __DMA1_CSELR
+#define DMA1_CH3_VARIANT __DMA1_CSELR
+#define DMA1_CH4_VARIANT __DMA1_CSELR
+#define DMA1_CH5_VARIANT __DMA1_CSELR
+#define DMA1_CH6_VARIANT __DMA1_CSELR
+#define DMA1_CH7_VARIANT __DMA1_CSELR
+#define DMA1_CH8_VARIANT __DMA1_CSELR
+#define DMA2_CH1_VARIANT __DMA2_CSELR
+#define DMA2_CH2_VARIANT __DMA2_CSELR
+#define DMA2_CH3_VARIANT __DMA2_CSELR
+#define DMA2_CH4_VARIANT __DMA2_CSELR
+#define DMA2_CH5_VARIANT __DMA2_CSELR
+#define DMA2_CH6_VARIANT __DMA2_CSELR
+#define DMA2_CH7_VARIANT __DMA2_CSELR
+#define DMA2_CH8_VARIANT __DMA2_CSELR
+
+#elif STM32_DMA_SUPPORTS_DMAMUX == TRUE
+
+#define DMAMUX1_CHANNEL(id) (DMAMUX1_BASE + ((id) * 4U))
+
+#define DMA1_CH1_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(0))
+#define DMA1_CH2_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(1))
+#define DMA1_CH3_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(2))
+#define DMA1_CH4_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(3))
+#define DMA1_CH5_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(4))
+#define DMA1_CH6_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(5))
+#define DMA1_CH7_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(6))
+#define DMA1_CH8_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(7))
+#define DMA2_CH1_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(8))
+#define DMA2_CH2_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(9))
+#define DMA2_CH3_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(10))
+#define DMA2_CH4_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(11))
+#define DMA2_CH5_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(12))
+#define DMA2_CH6_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(13))
+#define DMA2_CH7_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(14))
+#define DMA2_CH8_VARIANT ((DMAMUX_Channel_TypeDef *)DMAMUX1_CHANNEL(15))
+
+#else /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */
+
+#define DMA1_CH1_VARIANT 0
+#define DMA1_CH2_VARIANT 0
+#define DMA1_CH3_VARIANT 0
+#define DMA1_CH4_VARIANT 0
+#define DMA1_CH5_VARIANT 0
+#define DMA1_CH6_VARIANT 0
+#define DMA1_CH7_VARIANT 0
+#define DMA2_CH1_VARIANT 0
+#define DMA2_CH2_VARIANT 0
+#define DMA2_CH3_VARIANT 0
+#define DMA2_CH4_VARIANT 0
+#define DMA2_CH5_VARIANT 0
+#define DMA2_CH6_VARIANT 0
+#define DMA2_CH7_VARIANT 0
+
+#endif /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */
+
+/*
+ * Default ISR collision masks.
+ */
+#if !defined(STM32_DMA1_CH1_CMASK)
+#define STM32_DMA1_CH1_CMASK (1U << 0U)
+#endif
+
+#if !defined(STM32_DMA1_CH2_CMASK)
+#define STM32_DMA1_CH2_CMASK (1U << 1U)
+#endif
+
+#if !defined(STM32_DMA1_CH3_CMASK)
+#define STM32_DMA1_CH3_CMASK (1U << 2U)
+#endif
+
+#if !defined(STM32_DMA1_CH4_CMASK)
+#define STM32_DMA1_CH4_CMASK (1U << 3U)
+#endif
+
+#if !defined(STM32_DMA1_CH5_CMASK)
+#define STM32_DMA1_CH5_CMASK (1U << 4U)
+#endif
+
+#if !defined(STM32_DMA1_CH6_CMASK)
+#define STM32_DMA1_CH6_CMASK (1U << 5U)
+#endif
+
+#if !defined(STM32_DMA1_CH7_CMASK)
+#define STM32_DMA1_CH7_CMASK (1U << 6U)
+#endif
+
+#if !defined(STM32_DMA1_CH8_CMASK)
+#define STM32_DMA1_CH8_CMASK (1U << 7U)
+#endif
+
+#if !defined(STM32_DMA2_CH1_CMASK)
+#define STM32_DMA2_CH1_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 0U))
+#endif
+
+#if !defined(STM32_DMA2_CH2_CMASK)
+#define STM32_DMA2_CH2_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 1U))
+#endif
+
+#if !defined(STM32_DMA2_CH3_CMASK)
+#define STM32_DMA2_CH3_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 2U))
+#endif
+
+#if !defined(STM32_DMA2_CH4_CMASK)
+#define STM32_DMA2_CH4_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 3U))
+#endif
+
+#if !defined(STM32_DMA2_CH5_CMASK)
+#define STM32_DMA2_CH5_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 4U))
+#endif
+
+#if !defined(STM32_DMA2_CH6_CMASK)
+#define STM32_DMA2_CH6_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 5U))
+#endif
+
+#if !defined(STM32_DMA2_CH7_CMASK)
+#define STM32_DMA2_CH7_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 6U))
+#endif
+
+#if !defined(STM32_DMA2_CH8_CMASK)
+#define STM32_DMA2_CH8_CMASK (1U << (STM32_DMA1_NUM_CHANNELS + 7U))
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief DMA streams descriptors.
+ * @details This table keeps the association between an unique stream
+ * identifier and the involved physical registers.
+ * @note Don't use this array directly, use the appropriate wrapper macros
+ * instead: @p STM32_DMA1_STREAM1, @p STM32_DMA1_STREAM2 etc.
+ */
+const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = {
+#if STM32_DMA1_NUM_CHANNELS > 0
+ {DMA1, DMA1_Channel1, STM32_DMA1_CH1_CMASK, DMA1_CH1_VARIANT, 0, 0, STM32_DMA1_CH1_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 1
+ {DMA1, DMA1_Channel2, STM32_DMA1_CH2_CMASK, DMA1_CH2_VARIANT, 4, 1, STM32_DMA1_CH2_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 2
+ {DMA1, DMA1_Channel3, STM32_DMA1_CH3_CMASK, DMA1_CH3_VARIANT, 8, 2, STM32_DMA1_CH3_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 3
+ {DMA1, DMA1_Channel4, STM32_DMA1_CH4_CMASK, DMA1_CH4_VARIANT, 12, 3, STM32_DMA1_CH4_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 4
+ {DMA1, DMA1_Channel5, STM32_DMA1_CH5_CMASK, DMA1_CH5_VARIANT, 16, 4, STM32_DMA1_CH5_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 5
+ {DMA1, DMA1_Channel6, STM32_DMA1_CH6_CMASK, DMA1_CH6_VARIANT, 20, 5, STM32_DMA1_CH6_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 6
+ {DMA1, DMA1_Channel7, STM32_DMA1_CH7_CMASK, DMA1_CH7_VARIANT, 24, 6, STM32_DMA1_CH7_NUMBER},
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 7
+ {DMA1, DMA1_Channel8, STM32_DMA1_CH8_CMASK, DMA1_CH8_VARIANT, 28, 7, STM32_DMA1_CH8_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 0
+ {DMA2, DMA2_Channel1, STM32_DMA2_CH1_CMASK, DMA2_CH1_VARIANT, 0, 0 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH1_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 1
+ {DMA2, DMA2_Channel2, STM32_DMA2_CH2_CMASK, DMA2_CH2_VARIANT, 4, 1 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH2_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 2
+ {DMA2, DMA2_Channel3, STM32_DMA2_CH3_CMASK, DMA2_CH3_VARIANT, 8, 2 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH3_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 3
+ {DMA2, DMA2_Channel4, STM32_DMA2_CH4_CMASK, DMA2_CH4_VARIANT, 12, 3 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH4_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 4
+ {DMA2, DMA2_Channel5, STM32_DMA2_CH5_CMASK, DMA2_CH5_VARIANT, 16, 4 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH5_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 5
+ {DMA2, DMA2_Channel6, STM32_DMA2_CH6_CMASK, DMA2_CH6_VARIANT, 20, 5 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH6_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 6
+ {DMA2, DMA2_Channel7, STM32_DMA2_CH7_CMASK, DMA2_CH7_VARIANT, 24, 6 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH7_NUMBER},
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 7
+ {DMA2, DMA2_Channel8, STM32_DMA2_CH8_CMASK, DMA2_CH8_VARIANT, 28, 7 + STM32_DMA1_NUM_CHANNELS, STM32_DMA2_CH8_NUMBER},
+#endif
+};
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Global DMA-related data structures.
+ */
+static struct {
+ /**
+ * @brief Mask of the allocated streams.
+ */
+ uint32_t allocated_mask;
+ /**
+ * @brief Mask of the enabled streams ISRs.
+ */
+ uint32_t isr_mask;
+ /**
+ * @brief DMA IRQ redirectors.
+ */
+ struct {
+ /**
+ * @brief DMA callback function.
+ */
+ stm32_dmaisr_t func;
+ /**
+ * @brief DMA callback parameter.
+ */
+ void *param;
+ } streams[STM32_DMA_STREAMS];
+} dma;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if defined(STM32_DMA1_CH1_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 1 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH2_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 2 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH3_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 3 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH4_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 4 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH5_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 5 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH6_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 6 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH7_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 7 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA1_CH8_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA1 stream 8 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH8_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA1_STREAM8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH1_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 1 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH2_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 2 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH3_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 3 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH4_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 4 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH5_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 5 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH6_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 6 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH7_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 7 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if defined(STM32_DMA2_CH8_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 stream 8 shared ISR.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH8_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmaServeInterrupt(STM32_DMA2_STREAM8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 DMA helper initialization.
+ *
+ * @init
+ */
+void dmaInit(void) {
+ int i;
+
+ dma.allocated_mask = 0U;
+ dma.isr_mask = 0U;
+ for (i = 0; i < STM32_DMA_STREAMS; i++) {
+ _stm32_dma_streams[i].channel->CCR = STM32_DMA_CCR_RESET_VALUE;
+ dma.streams[i].func = NULL;
+ }
+ DMA1->IFCR = 0xFFFFFFFFU;
+#if STM32_DMA2_NUM_CHANNELS > 0
+ DMA2->IFCR = 0xFFFFFFFFU;
+#endif
+}
+
+/**
+ * @brief Allocates a DMA stream.
+ * @details The stream is allocated and, if required, the DMA clock enabled.
+ * The function also enables the IRQ vector associated to the stream
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific stream or:
+ * - @p STM32_DMA_STREAM_ID_ANY for any stream.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream
+ * on DMA1.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream
+ * on DMA2.
+ * .
+ * @param[in] priority IRQ priority for the DMA stream
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_dma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
+ *
+ * @iclass
+ */
+const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param) {
+ uint32_t i, startid, endid;
+
+ osalDbgCheckClassI();
+
+ if (id < STM32_DMA_STREAMS) {
+ startid = id;
+ endid = id;
+ }
+#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
+ else if (id == STM32_DMA_STREAM_ID_ANY) {
+ startid = 0U;
+ endid = STM32_DMA_STREAMS - 1U;
+ }
+ else if (id == STM32_DMA_STREAM_ID_ANY_DMA1) {
+ startid = 0U;
+ endid = STM32_DMA1_NUM_CHANNELS - 1U;
+ }
+#if STM32_DMA2_NUM_CHANNELS > 0
+ else if (id == STM32_DMA_STREAM_ID_ANY_DMA2) {
+ startid = STM32_DMA1_NUM_CHANNELS;
+ endid = STM32_DMA_STREAMS - 1U;
+ }
+#endif
+#endif
+ else {
+ osalDbgCheck(false);
+ return NULL;
+ }
+
+ for (i = startid; i <= endid; i++) {
+ uint32_t mask = (1U << i);
+ if ((dma.allocated_mask & mask) == 0U) {
+ const stm32_dma_stream_t *dmastp = STM32_DMA_STREAM(i);
+
+ /* Installs the DMA handler.*/
+ dma.streams[i].func = func;
+ dma.streams[i].param = param;
+ dma.allocated_mask |= mask;
+
+ /* Enabling DMA clocks required by the current streams set.*/
+ if ((STM32_DMA1_STREAMS_MASK & mask) != 0U) {
+ rccEnableDMA1(true);
+ }
+#if STM32_DMA2_NUM_CHANNELS > 0
+ if ((STM32_DMA2_STREAMS_MASK & mask) != 0U) {
+ rccEnableDMA2(true);
+ }
+#endif
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccEnableDMAMUX)
+ /* Enabling DMAMUX if present.*/
+ if (dma.allocated_mask != 0U) {
+ rccEnableDMAMUX(true);
+ }
+#endif
+
+ /* Enables the associated IRQ vector if not already enabled and if a
+ callback is defined.*/
+ if (func != NULL) {
+ if ((dma.isr_mask & dmastp->cmask) == 0U) {
+ nvicEnableVector(dmastp->vector, priority);
+ }
+ dma.isr_mask |= mask;
+ }
+
+ /* Putting the stream in a known state.*/
+ dmaStreamDisable(dmastp);
+ dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE;
+
+ return dmastp;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Allocates a DMA stream.
+ * @details The stream is allocated and, if required, the DMA clock enabled.
+ * The function also enables the IRQ vector associated to the stream
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific stream or:
+ * - @p STM32_DMA_STREAM_ID_ANY for any stream.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream
+ * on DMA1.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream
+ * on DMA2.
+ * .
+ * @param[in] priority IRQ priority for the DMA stream
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_dma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
+ *
+ * @api
+ */
+const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param) {
+ const stm32_dma_stream_t *dmastp;
+
+ osalSysLock();
+ dmastp = dmaStreamAllocI(id, priority, func, param);
+ osalSysUnlock();
+
+ return dmastp;
+}
+
+/**
+ * @brief Releases a DMA stream.
+ * @details The stream is freed and, if required, the DMA clock disabled.
+ * Trying to release a unallocated stream is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @iclass
+ */
+void dmaStreamFreeI(const stm32_dma_stream_t *dmastp) {
+ uint32_t selfindex = (uint32_t)dmastp->selfindex;
+
+ osalDbgCheck(dmastp != NULL);
+
+ /* Check if the streams is not taken.*/
+ osalDbgAssert((dma.allocated_mask & (1 << selfindex)) != 0U,
+ "not allocated");
+
+ /* Marks the stream as not allocated.*/
+ dma.allocated_mask &= ~(1U << selfindex);
+ dma.isr_mask &= ~(1U << selfindex);
+
+ /* Disables the associated IRQ vector if it is no more in use.*/
+ if ((dma.isr_mask & dmastp->cmask) == 0U) {
+ nvicDisableVector(dmastp->vector);
+ }
+
+ /* Removes the DMA handler.*/
+ dma.streams[selfindex].func = NULL;
+ dma.streams[selfindex].param = NULL;
+
+ /* Shutting down clocks that are no more required, if any.*/
+ if ((dma.allocated_mask & STM32_DMA1_STREAMS_MASK) == 0U) {
+ rccDisableDMA1();
+ }
+#if STM32_DMA2_NUM_CHANNELS > 0
+ if ((dma.allocated_mask & STM32_DMA2_STREAMS_MASK) == 0U) {
+ rccDisableDMA2();
+ }
+#endif
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccDisableDMAMUX)
+ /* Shutting down DMAMUX if present.*/
+ if (dma.allocated_mask == 0U) {
+ rccDisableDMAMUX();
+ }
+#endif
+}
+
+/**
+ * @brief Releases a DMA stream.
+ * @details The stream is freed and, if required, the DMA clock disabled.
+ * Trying to release a unallocated stream is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @api
+ */
+void dmaStreamFree(const stm32_dma_stream_t *dmastp) {
+
+ osalSysLock();
+ dmaStreamFreeI(dmastp);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Serves a DMA IRQ.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+void dmaServeInterrupt(const stm32_dma_stream_t *dmastp) {
+ uint32_t flags;
+ uint32_t selfindex = (uint32_t)dmastp->selfindex;
+
+ flags = (dmastp->dma->ISR >> dmastp->shift) & STM32_DMA_ISR_MASK;
+ if (flags & dmastp->channel->CCR) {
+ dmastp->dma->IFCR = flags << dmastp->shift;
+ if (dma.streams[selfindex].func) {
+ dma.streams[selfindex].func(dma.streams[selfindex].param, flags);
+ }
+ }
+}
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Associates a peripheral request to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ *
+ * @param[in] dmastp pointer to a @p stm32_dma_stream_t structure
+ * @param[in] per peripheral identifier
+ *
+ * @special
+ */
+void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per) {
+
+ osalDbgCheck(per < 256U);
+
+ dmastp->mux->CCR = per;
+}
+#endif
+
+#endif /* STM32_DMA_REQUIRED */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h new file mode 100644 index 0000000..54b6bde --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h @@ -0,0 +1,554 @@ +/*
+ 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 DMAv1/stm32_dma.h
+ * @brief DMA helper driver header.
+ * @note This driver uses the new naming convention used for the STM32F2xx
+ * so the "DMA channels" are referred as "DMA streams".
+ *
+ * @addtogroup STM32_DMA
+ * @{
+ */
+
+#ifndef STM32_DMA_H
+#define STM32_DMA_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief DMA capability.
+ * @details if @p TRUE then the DMA is able of burst transfers, FIFOs,
+ * scatter gather and other advanced features.
+ */
+#define STM32_DMA_ADVANCED FALSE
+
+/**
+ * @brief Total number of DMA streams.
+ * @details This is the total number of streams among all the DMA units.
+ */
+#define STM32_DMA_STREAMS (STM32_DMA1_NUM_CHANNELS + \
+ STM32_DMA2_NUM_CHANNELS)
+
+/**
+ * @brief Mask of the ISR bits passed to the DMA callback functions.
+ */
+#define STM32_DMA_ISR_MASK 0x0E
+
+/**
+ * @brief Returns the request line associated to the specified stream.
+ * @note In some STM32 manuals the request line is named confusingly
+ * channel.
+ *
+ * @param[in] id the unique numeric stream identifier
+ * @param[in] c a stream/request association word, one request per
+ * nibble
+ * @return Returns the request associated to the stream.
+ */
+#define STM32_DMA_GETCHANNEL(id, c) \
+ (((uint32_t)(c) >> (((uint32_t)(id) % (uint32_t)STM32_DMA1_NUM_CHANNELS) * 4U)) & 15U)
+
+/**
+ * @brief Checks if a DMA priority is within the valid range.
+ * @param[in] prio DMA priority
+ *
+ * @retval The check result.
+ * @retval false invalid DMA priority.
+ * @retval true correct DMA priority.
+ */
+#define STM32_DMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U))
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == FALSE) || defined(_DOXYGEN__)
+/**
+ * @brief Checks if a DMA stream id is within the valid range.
+ *
+ * @param[in] id DMA stream id
+ * @retval The check result.
+ * @retval false invalid DMA channel.
+ * @retval true correct DMA channel.
+ */
+#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) < STM32_DMA_STREAMS))
+#else /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */
+#if STM32_DMA2_NUM_CHANNELS > 0
+#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) <= (STM32_DMA_STREAMS + 2)))
+#else
+#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) <= (STM32_DMA_STREAMS + 1)))
+#endif
+#endif /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */
+
+/**
+ * @brief Returns an unique numeric identifier for a DMA stream.
+ *
+ * @param[in] dma the DMA unit number
+ * @param[in] stream the stream number
+ * @return An unique numeric stream identifier.
+ */
+#define STM32_DMA_STREAM_ID(dma, stream) \
+ ((((dma) - 1) * STM32_DMA1_NUM_CHANNELS) + ((stream) - 1))
+
+/**
+ * @brief Returns a DMA stream identifier mask.
+ *
+ *
+ * @param[in] dma the DMA unit number
+ * @param[in] stream the stream number
+ * @return A DMA stream identifier mask.
+ */
+#define STM32_DMA_STREAM_ID_MSK(dma, stream) \
+ (1U << STM32_DMA_STREAM_ID(dma, stream))
+
+/**
+ * @brief Checks if a DMA stream unique identifier belongs to a mask.
+ *
+ * @param[in] id the stream numeric identifier
+ * @param[in] mask the stream numeric identifiers mask
+ *
+ * @retval The check result.
+ * @retval false id does not belong to the mask.
+ * @retval true id belongs to the mask.
+ */
+#define STM32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask)))
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(_DOXYGEN__)
+/**
+ * @name Special stream identifiers
+ * @{
+ */
+#define STM32_DMA_STREAM_ID_ANY STM32_DMA_STREAMS
+#define STM32_DMA_STREAM_ID_ANY_DMA1 (STM32_DMA_STREAM_ID_ANY + 1)
+#if STM32_DMA2_NUM_CHANNELS > 0
+#define STM32_DMA_STREAM_ID_ANY_DMA2 (STM32_DMA_STREAM_ID_ANY_DMA1 + 1)
+#endif
+/** @} */
+#endif
+
+/**
+ * @name DMA streams identifiers
+ * @{
+ */
+/**
+ * @brief Returns a pointer to a stm32_dma_stream_t structure.
+ *
+ * @param[in] id the stream numeric identifier
+ * @return A pointer to the stm32_dma_stream_t constant structure
+ * associated to the DMA stream.
+ */
+#define STM32_DMA_STREAM(id) (&_stm32_dma_streams[id])
+
+#if STM32_DMA1_NUM_CHANNELS > 0
+#define STM32_DMA1_STREAM1 STM32_DMA_STREAM(0)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 1
+#define STM32_DMA1_STREAM2 STM32_DMA_STREAM(1)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 2
+#define STM32_DMA1_STREAM3 STM32_DMA_STREAM(2)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 3
+#define STM32_DMA1_STREAM4 STM32_DMA_STREAM(3)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 4
+#define STM32_DMA1_STREAM5 STM32_DMA_STREAM(4)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 5
+#define STM32_DMA1_STREAM6 STM32_DMA_STREAM(5)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 6
+#define STM32_DMA1_STREAM7 STM32_DMA_STREAM(6)
+#endif
+#if STM32_DMA1_NUM_CHANNELS > 7
+#define STM32_DMA1_STREAM8 STM32_DMA_STREAM(7)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 0
+#define STM32_DMA2_STREAM1 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 0)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 1
+#define STM32_DMA2_STREAM2 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 1)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 2
+#define STM32_DMA2_STREAM3 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 2)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 3
+#define STM32_DMA2_STREAM4 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 3)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 4
+#define STM32_DMA2_STREAM5 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 4)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 5
+#define STM32_DMA2_STREAM6 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 5)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 6
+#define STM32_DMA2_STREAM7 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 6)
+#endif
+#if STM32_DMA2_NUM_CHANNELS > 7
+#define STM32_DMA2_STREAM8 STM32_DMA_STREAM(STM32_DMA1_NUM_CHANNELS + 7)
+#endif
+/** @} */
+
+/**
+ * @name CR register constants common to all DMA types
+ * @{
+ */
+#define STM32_DMA_CCR_RESET_VALUE 0x00000000U
+#define STM32_DMA_CR_EN DMA_CCR_EN
+#define STM32_DMA_CR_TEIE DMA_CCR_TEIE
+#define STM32_DMA_CR_HTIE DMA_CCR_HTIE
+#define STM32_DMA_CR_TCIE DMA_CCR_TCIE
+#define STM32_DMA_CR_DIR_MASK (DMA_CCR_DIR | DMA_CCR_MEM2MEM)
+#define STM32_DMA_CR_DIR_P2M 0U
+#define STM32_DMA_CR_DIR_M2P DMA_CCR_DIR
+#define STM32_DMA_CR_DIR_M2M DMA_CCR_MEM2MEM
+#define STM32_DMA_CR_CIRC DMA_CCR_CIRC
+#define STM32_DMA_CR_PINC DMA_CCR_PINC
+#define STM32_DMA_CR_MINC DMA_CCR_MINC
+#define STM32_DMA_CR_PSIZE_MASK DMA_CCR_PSIZE
+#define STM32_DMA_CR_PSIZE_BYTE 0U
+#define STM32_DMA_CR_PSIZE_HWORD DMA_CCR_PSIZE_0
+#define STM32_DMA_CR_PSIZE_WORD DMA_CCR_PSIZE_1
+#define STM32_DMA_CR_MSIZE_MASK DMA_CCR_MSIZE
+#define STM32_DMA_CR_MSIZE_BYTE 0U
+#define STM32_DMA_CR_MSIZE_HWORD DMA_CCR_MSIZE_0
+#define STM32_DMA_CR_MSIZE_WORD DMA_CCR_MSIZE_1
+#define STM32_DMA_CR_SIZE_MASK (STM32_DMA_CR_PSIZE_MASK | \
+ STM32_DMA_CR_MSIZE_MASK)
+#define STM32_DMA_CR_PL_MASK DMA_CCR_PL
+#define STM32_DMA_CR_PL(n) ((n) << 12U)
+/** @} */
+
+/**
+ * @name Request line selector macro
+ * @{
+ */
+#if STM32_DMA_SUPPORTS_CSELR || defined(__DOXYGEN__)
+#define STM32_DMA_CR_CHSEL_MASK (15U << 16U)
+#define STM32_DMA_CR_CHSEL(n) ((n) << 16U)
+#else
+#define STM32_DMA_CR_CHSEL_MASK 0U
+#define STM32_DMA_CR_CHSEL(n) 0U
+#endif
+/** @} */
+
+/**
+ * @name CR register constants only found in enhanced DMA
+ * @{
+ */
+#define STM32_DMA_CR_DMEIE 0U /**< @brief Ignored by normal DMA. */
+/** @} */
+
+/**
+ * @name Status flags passed to the ISR callbacks
+ * @{
+ */
+#define STM32_DMA_ISR_FEIF 0U
+#define STM32_DMA_ISR_DMEIF 0U
+#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1
+#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1
+#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_DMA_SUPPORTS_DMAMUX)
+#error "STM32_DMA_SUPPORTS_DMAMUX not defined in registry"
+#endif
+
+#if !defined(STM32_DMA_SUPPORTS_CSELR)
+#error "STM32_DMA_SUPPORTS_CSELR not defined in registry"
+#endif
+
+#if STM32_DMA_SUPPORTS_DMAMUX && STM32_DMA_SUPPORTS_CSELR
+#error "STM32_DMA_SUPPORTS_DMAMUX and STM32_DMA_SUPPORTS_CSELR both TRUE"
+#endif
+
+#if !defined(STM32_DMA1_NUM_CHANNELS)
+#error "STM32_DMA1_NUM_CHANNELS not defined in registry"
+#endif
+
+#if !defined(STM32_DMA2_NUM_CHANNELS)
+#error "STM32_DMA2_NUM_CHANNELS not defined in registry"
+#endif
+
+#if (STM32_DMA1_NUM_CHANNELS < 0) || (STM32_DMA1_NUM_CHANNELS > 8)
+#error "unsupported channels configuration"
+#endif
+
+#if (STM32_DMA2_NUM_CHANNELS < 0) || (STM32_DMA2_NUM_CHANNELS > 8)
+#error "unsupported channels configuration"
+#endif
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+#include "stm32_dmamux.h"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a DMA callback.
+ *
+ * @param[in] p parameter for the registered function
+ * @param[in] flags pre-shifted content of the ISR register, the bits
+ * are aligned to bit zero
+ */
+typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags);
+
+/**
+ * @brief STM32 DMA stream descriptor structure.
+ */
+typedef struct {
+ DMA_TypeDef *dma; /**< @brief Associated DMA. */
+ DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */
+ uint32_t cmask; /**< @brief Mask of streams sharing
+ the same ISR. */
+#if (STM32_DMA_SUPPORTS_CSELR == TRUE) || defined(__DOXYGEN__)
+ volatile uint32_t *cselr; /**< @brief Associated CSELR reg. */
+#elif STM32_DMA_SUPPORTS_DMAMUX == TRUE
+ DMAMUX_Channel_TypeDef *mux; /**< @brief Associated DMA mux. */
+#else
+ uint8_t dummy; /**< @brief Filler. */
+#endif
+ uint8_t shift; /**< @brief Bit offset in ISR, IFCR
+ and CSELR registers. */
+ uint8_t selfindex; /**< @brief Index to self in array. */
+ uint8_t vector; /**< @brief Associated IRQ vector. */
+} stm32_dma_stream_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Associates a peripheral data register to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] addr value to be written in the CPAR register
+ *
+ * @special
+ */
+#define dmaStreamSetPeripheral(dmastp, addr) { \
+ (dmastp)->channel->CPAR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Associates a memory destination to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] addr value to be written in the CMAR register
+ *
+ * @special
+ */
+#define dmaStreamSetMemory0(dmastp, addr) { \
+ (dmastp)->channel->CMAR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Sets the number of transfers to be performed.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] size value to be written in the CNDTR register
+ *
+ * @special
+ */
+#define dmaStreamSetTransactionSize(dmastp, size) { \
+ (dmastp)->channel->CNDTR = (uint32_t)(size); \
+}
+
+/**
+ * @brief Returns the number of transfers to be performed.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @return The number of transfers to be performed.
+ *
+ * @special
+ */
+#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->channel->CNDTR))
+
+/**
+ * @brief Programs the stream mode settings.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] mode value to be written in the CCR register
+ *
+ * @special
+ */
+#if STM32_DMA_SUPPORTS_CSELR || defined(__DOXYGEN__)
+#define dmaStreamSetMode(dmastp, mode) { \
+ uint32_t cselr = *(dmastp)->cselr; \
+ cselr &= ~(0x0000000FU << (dmastp)->shift); \
+ cselr |= (((uint32_t)(mode) >> 16U) << (dmastp)->shift); \
+ *(dmastp)->cselr = cselr; \
+ (dmastp)->channel->CCR = (uint32_t)(mode); \
+}
+#else
+#define dmaStreamSetMode(dmastp, mode) { \
+ (dmastp)->channel->CCR = (uint32_t)(mode); \
+}
+#endif
+
+/**
+ * @brief DMA stream enable.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+#define dmaStreamEnable(dmastp) { \
+ (dmastp)->channel->CCR |= STM32_DMA_CR_EN; \
+}
+
+/**
+ * @brief DMA stream disable.
+ * @details The function disables the specified stream and then clears any
+ * pending interrupt.
+ * @note This function can be invoked in both ISR or thread context.
+ * @note Interrupts enabling flags are set to zero after this call, see
+ * bug 3607518.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+#define dmaStreamDisable(dmastp) { \
+ (dmastp)->channel->CCR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_EN); \
+ dmaStreamClearInterrupt(dmastp); \
+}
+
+/**
+ * @brief DMA stream interrupt sources clear.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+#define dmaStreamClearInterrupt(dmastp) { \
+ (dmastp)->dma->IFCR = STM32_DMA_ISR_MASK << (dmastp)->shift; \
+}
+
+/**
+ * @brief Starts a memory to memory operation using the specified stream.
+ * @note The default transfer data mode is "byte to byte" but it can be
+ * changed by specifying extra options in the @p mode parameter.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] mode value to be written in the CCR register, this value
+ * is implicitly ORed with:
+ * - @p STM32_DMA_CR_MINC
+ * - @p STM32_DMA_CR_PINC
+ * - @p STM32_DMA_CR_DIR_M2M
+ * - @p STM32_DMA_CR_EN
+ * .
+ * @param[in] src source address
+ * @param[in] dst destination address
+ * @param[in] n number of data units to copy
+ */
+#define dmaStartMemCopy(dmastp, mode, src, dst, n) { \
+ dmaStreamSetPeripheral(dmastp, src); \
+ dmaStreamSetMemory0(dmastp, dst); \
+ dmaStreamSetTransactionSize(dmastp, n); \
+ dmaStreamSetMode(dmastp, (mode) | \
+ STM32_DMA_CR_MINC | STM32_DMA_CR_PINC | \
+ STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_EN); \
+}
+
+/**
+ * @brief Polled wait for DMA transfer end.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamRelease().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ */
+#define dmaWaitCompletion(dmastp) { \
+ while ((dmastp)->channel->CNDTR > 0U) \
+ ; \
+ dmaStreamDisable(dmastp); \
+}
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void dmaInit(void);
+ const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param);
+ const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param);
+ void dmaStreamFreeI(const stm32_dma_stream_t *dmastp);
+ void dmaStreamFree(const stm32_dma_stream_t *dmastp);
+ void dmaServeInterrupt(const stm32_dma_stream_t *dmastp);
+#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
+ void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_DMA_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc new file mode 100644 index 0000000..c67f5b4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch23.inc @@ -0,0 +1,78 @@ +/* + 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 DMAv1/stm32_dma1_ch23.inc + * @brief Shared DMA1 Channels 2 and 3 handler. + * + * @addtogroup STM32_DMA1_CH23_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Other checks.*/ +#if !defined(STM32_DMA1_CH23_HANDLER) +#error "STM32_DMA1_CH23_HANDLER not defined in stm32_isr.h" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) +/** + * @brief DMA1 streams 2 and 3 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH23_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + /* Check on channel 2.*/ + dmaServeInterrupt(STM32_DMA1_STREAM2); + + /* Check on channel 3.*/ + dmaServeInterrupt(STM32_DMA1_STREAM3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc new file mode 100644 index 0000000..1de4597 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv1/stm32_dma1_ch4567.inc @@ -0,0 +1,84 @@ +/* + 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 DMAv1/stm32_dma1_ch4567.inc + * @brief Shared DMA1 Channels 4, 5, 6 and 7 handler. + * + * @addtogroup STM32_DMA1_CH4567_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Other checks.*/ +#if !defined(STM32_DMA1_CH4567_HANDLER) +#error "STM32_DMA1_CH4567_HANDLER not defined in stm32_isr.h" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) +/** + * @brief DMA1 streams 4, 5, 6 and 7 shared ISR. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH4567_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + /* Check on channel 4.*/ + dmaServeInterrupt(STM32_DMA1_STREAM4); + + /* Check on channel 5.*/ + dmaServeInterrupt(STM32_DMA1_STREAM5); + + /* Check on channel 6.*/ + dmaServeInterrupt(STM32_DMA1_STREAM6); + + /* Check on channel 7.*/ + dmaServeInterrupt(STM32_DMA1_STREAM7); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk new file mode 100644 index 0000000..bdc468a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt new file mode 100644 index 0000000..4c01d83 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/notes.txt @@ -0,0 +1,18 @@ +STM32 DMAv2 driver.
+
+Driver capability:
+
+- The driver supports the STM32 enhanced DMA controller found on F2, F4 and
+ F7 sub-families.
+- Support for automatic the channel selection.
+- Support for cache flushing and invalidation.
+
+The file registry must export:
+
+STM32_ADVANCED_DMA - TRUE not used by the DMA drivers but other
+ drivers use it to enable checks on DMA
+ channels. Probably will be removed in the
+ future.
+STM32_HAS_DMAx - Support for DMA unit "x" (1..2).
+STM32_DMAx_CHn_HANDLER - Vector name for channel "n" (0..7).
+STM32_DMAn_CHx_NUMBER - Vector number for channel "n" (0..7).
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c new file mode 100644 index 0000000..10b4b68 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c @@ -0,0 +1,675 @@ +/*
+ 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 DMAv2/stm32_dma.c
+ * @brief Enhanced DMA helper driver code.
+ *
+ * @addtogroup STM32_DMA
+ * @details DMA sharing helper driver. In the STM32 the DMA streams are a
+ * shared resource, this driver allows to allocate and free DMA
+ * streams at runtime in order to allow all the other device
+ * drivers to coordinate the access to the resource.
+ * @note The DMA ISR handlers are all declared into this module because
+ * sharing, the various device drivers can associate a callback to
+ * ISRs when allocating streams.
+ * @{
+ */
+
+#include "hal.h"
+
+/* The following macro is only defined if some driver requiring DMA services
+ has been enabled.*/
+#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/**
+ * @brief Mask of the DMA1 streams in @p dma.allocated_mask.
+ */
+#define STM32_DMA1_STREAMS_MASK 0x000000FFU
+
+/**
+ * @brief Mask of the DMA2 streams in @p dma.allocated_mask.
+ */
+#define STM32_DMA2_STREAMS_MASK 0x0000FF00U
+
+#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
+
+#define DMA1_CH0_VARIANT DMAMUX1_Channel0
+#define DMA1_CH1_VARIANT DMAMUX1_Channel1
+#define DMA1_CH2_VARIANT DMAMUX1_Channel2
+#define DMA1_CH3_VARIANT DMAMUX1_Channel3
+#define DMA1_CH4_VARIANT DMAMUX1_Channel4
+#define DMA1_CH5_VARIANT DMAMUX1_Channel5
+#define DMA1_CH6_VARIANT DMAMUX1_Channel6
+#define DMA1_CH7_VARIANT DMAMUX1_Channel7
+#define DMA2_CH0_VARIANT DMAMUX1_Channel8
+#define DMA2_CH1_VARIANT DMAMUX1_Channel9
+#define DMA2_CH2_VARIANT DMAMUX1_Channel10
+#define DMA2_CH3_VARIANT DMAMUX1_Channel11
+#define DMA2_CH4_VARIANT DMAMUX1_Channel12
+#define DMA2_CH5_VARIANT DMAMUX1_Channel13
+#define DMA2_CH6_VARIANT DMAMUX1_Channel14
+#define DMA2_CH7_VARIANT DMAMUX1_Channel15
+
+#else /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */
+
+#define DMA1_CH0_VARIANT 0
+#define DMA1_CH1_VARIANT 0
+#define DMA1_CH2_VARIANT 0
+#define DMA1_CH3_VARIANT 0
+#define DMA1_CH4_VARIANT 0
+#define DMA1_CH5_VARIANT 0
+#define DMA1_CH6_VARIANT 0
+#define DMA1_CH7_VARIANT 0
+#define DMA2_CH0_VARIANT 0
+#define DMA2_CH1_VARIANT 0
+#define DMA2_CH2_VARIANT 0
+#define DMA2_CH3_VARIANT 0
+#define DMA2_CH4_VARIANT 0
+#define DMA2_CH5_VARIANT 0
+#define DMA2_CH6_VARIANT 0
+#define DMA2_CH7_VARIANT 0
+
+#endif /* !(STM32_DMA_SUPPORTS_DMAMUX == TRUE) */
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief DMA streams descriptors.
+ * @details This table keeps the association between an unique stream
+ * identifier and the involved physical registers.
+ * @note Don't use this array directly, use the appropriate wrapper macros
+ * instead: @p STM32_DMA1_STREAM0, @p STM32_DMA1_STREAM1 etc.
+ */
+const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = {
+ {DMA1_Stream0, &DMA1->LIFCR, DMA1_CH0_VARIANT, 0, 0, STM32_DMA1_CH0_NUMBER},
+ {DMA1_Stream1, &DMA1->LIFCR, DMA1_CH1_VARIANT, 6, 1, STM32_DMA1_CH1_NUMBER},
+ {DMA1_Stream2, &DMA1->LIFCR, DMA1_CH2_VARIANT, 16, 2, STM32_DMA1_CH2_NUMBER},
+ {DMA1_Stream3, &DMA1->LIFCR, DMA1_CH3_VARIANT, 22, 3, STM32_DMA1_CH3_NUMBER},
+ {DMA1_Stream4, &DMA1->HIFCR, DMA1_CH4_VARIANT, 0, 4, STM32_DMA1_CH4_NUMBER},
+ {DMA1_Stream5, &DMA1->HIFCR, DMA1_CH5_VARIANT, 6, 5, STM32_DMA1_CH5_NUMBER},
+ {DMA1_Stream6, &DMA1->HIFCR, DMA1_CH6_VARIANT, 16, 6, STM32_DMA1_CH6_NUMBER},
+ {DMA1_Stream7, &DMA1->HIFCR, DMA1_CH7_VARIANT, 22, 7, STM32_DMA1_CH7_NUMBER},
+ {DMA2_Stream0, &DMA2->LIFCR, DMA2_CH0_VARIANT, 0, 8, STM32_DMA2_CH0_NUMBER},
+ {DMA2_Stream1, &DMA2->LIFCR, DMA2_CH1_VARIANT, 6, 9, STM32_DMA2_CH1_NUMBER},
+ {DMA2_Stream2, &DMA2->LIFCR, DMA2_CH2_VARIANT, 16, 10, STM32_DMA2_CH2_NUMBER},
+ {DMA2_Stream3, &DMA2->LIFCR, DMA2_CH3_VARIANT, 22, 11, STM32_DMA2_CH3_NUMBER},
+ {DMA2_Stream4, &DMA2->HIFCR, DMA2_CH4_VARIANT, 0, 12, STM32_DMA2_CH4_NUMBER},
+ {DMA2_Stream5, &DMA2->HIFCR, DMA2_CH5_VARIANT, 6, 13, STM32_DMA2_CH5_NUMBER},
+ {DMA2_Stream6, &DMA2->HIFCR, DMA2_CH6_VARIANT, 16, 14, STM32_DMA2_CH6_NUMBER},
+ {DMA2_Stream7, &DMA2->HIFCR, DMA2_CH7_VARIANT, 22, 15, STM32_DMA2_CH7_NUMBER},
+};
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Global DMA-related data structures.
+ */
+static struct {
+ /**
+ * @brief Mask of the allocated streams.
+ */
+ uint32_t allocated_mask;
+ /**
+ * @brief DMA IRQ redirectors.
+ */
+ struct {
+ /**
+ * @brief DMA callback function.
+ */
+ stm32_dmaisr_t func;
+ /**
+ * @brief DMA callback parameter.
+ */
+ void *param;
+ } streams[STM32_DMA_STREAMS];
+} dma;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief DMA1 stream 0 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH0_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->LISR >> 0U) & STM32_DMA_ISR_MASK;
+ DMA1->LIFCR = flags << 0U;
+ if (dma.streams[0].func)
+ dma.streams[0].func(dma.streams[0].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 1 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH1_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->LISR >> 6U) & STM32_DMA_ISR_MASK;
+ DMA1->LIFCR = flags << 6U;
+ if (dma.streams[1].func)
+ dma.streams[1].func(dma.streams[1].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 2 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH2_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->LISR >> 16U) & STM32_DMA_ISR_MASK;
+ DMA1->LIFCR = flags << 16U;
+ if (dma.streams[2].func)
+ dma.streams[2].func(dma.streams[2].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 3 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH3_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->LISR >> 22U) & STM32_DMA_ISR_MASK;
+ DMA1->LIFCR = flags << 22U;
+ if (dma.streams[3].func)
+ dma.streams[3].func(dma.streams[3].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 4 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH4_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->HISR >> 0U) & STM32_DMA_ISR_MASK;
+ DMA1->HIFCR = flags << 0U;
+ if (dma.streams[4].func)
+ dma.streams[4].func(dma.streams[4].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 5 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH5_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->HISR >> 6U) & STM32_DMA_ISR_MASK;
+ DMA1->HIFCR = flags << 6U;
+ if (dma.streams[5].func)
+ dma.streams[5].func(dma.streams[5].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 6 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH6_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->HISR >> 16U) & STM32_DMA_ISR_MASK;
+ DMA1->HIFCR = flags << 16U;
+ if (dma.streams[6].func)
+ dma.streams[6].func(dma.streams[6].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 stream 7 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA1_CH7_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA1->HISR >> 22U) & STM32_DMA_ISR_MASK;
+ DMA1->HIFCR = flags << 22U;
+ if (dma.streams[7].func)
+ dma.streams[7].func(dma.streams[7].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 0 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH0_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->LISR >> 0U) & STM32_DMA_ISR_MASK;
+ DMA2->LIFCR = flags << 0U;
+ if (dma.streams[8].func)
+ dma.streams[8].func(dma.streams[8].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 1 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH1_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->LISR >> 6U) & STM32_DMA_ISR_MASK;
+ DMA2->LIFCR = flags << 6U;
+ if (dma.streams[9].func)
+ dma.streams[9].func(dma.streams[9].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 2 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH2_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->LISR >> 16U) & STM32_DMA_ISR_MASK;
+ DMA2->LIFCR = flags << 16U;
+ if (dma.streams[10].func)
+ dma.streams[10].func(dma.streams[10].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 3 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH3_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->LISR >> 22U) & STM32_DMA_ISR_MASK;
+ DMA2->LIFCR = flags << 22U;
+ if (dma.streams[11].func)
+ dma.streams[11].func(dma.streams[11].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 4 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH4_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->HISR >> 0U) & STM32_DMA_ISR_MASK;
+ DMA2->HIFCR = flags << 0U;
+ if (dma.streams[12].func)
+ dma.streams[12].func(dma.streams[12].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 5 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->HISR >> 6U) & STM32_DMA_ISR_MASK;
+ DMA2->HIFCR = flags << 6U;
+ if (dma.streams[13].func)
+ dma.streams[13].func(dma.streams[13].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 6 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH6_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->HISR >> 16U) & STM32_DMA_ISR_MASK;
+ DMA2->HIFCR = flags << 16U;
+ if (dma.streams[14].func)
+ dma.streams[14].func(dma.streams[14].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 stream 7 shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) {
+ uint32_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ flags = (DMA2->HISR >> 22U) & STM32_DMA_ISR_MASK;
+ DMA2->HIFCR = flags << 22U;
+ if (dma.streams[15].func)
+ dma.streams[15].func(dma.streams[15].param, flags);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 DMA helper initialization.
+ *
+ * @init
+ */
+void dmaInit(void) {
+ unsigned i;
+
+ dma.allocated_mask = 0U;
+ for (i = 0U; i < STM32_DMA_STREAMS; i++) {
+ _stm32_dma_streams[i].stream->CR = STM32_DMA_CR_RESET_VALUE;
+ dma.streams[i].func = NULL;
+ }
+ DMA1->LIFCR = 0xFFFFFFFFU;
+ DMA1->HIFCR = 0xFFFFFFFFU;
+ DMA2->LIFCR = 0xFFFFFFFFU;
+ DMA2->HIFCR = 0xFFFFFFFFU;
+}
+
+/**
+ * @brief Allocates a DMA stream.
+ * @details The stream is allocated and, if required, the DMA clock enabled.
+ * The function also enables the IRQ vector associated to the stream
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific stream or:
+ * - @p STM32_DMA_STREAM_ID_ANY for any stream.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream
+ * on DMA1.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream
+ * on DMA2.
+ * .
+ * @param[in] priority IRQ priority for the DMA stream
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_dma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
+ *
+ * @iclass
+ */
+const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param) {
+ uint32_t i, startid, endid;
+
+ osalDbgCheckClassI();
+
+ if (id < STM32_DMA_STREAMS) {
+ startid = id;
+ endid = id;
+ }
+#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
+ else if (id == STM32_DMA_STREAM_ID_ANY) {
+ startid = 0U;
+ endid = STM32_DMA_STREAMS - 1U;
+ }
+ else if (id == STM32_DMA_STREAM_ID_ANY_DMA1) {
+ startid = 0U;
+ endid = (STM32_DMA_STREAMS / 2U) - 1U;
+ }
+ else if (id == STM32_DMA_STREAM_ID_ANY_DMA2) {
+ startid = (STM32_DMA_STREAMS / 2U) - 1U;
+ endid = STM32_DMA_STREAMS - 1U;
+ }
+#endif
+ else {
+ osalDbgCheck(false);
+ return NULL;
+ }
+
+ for (i = startid; i <= endid; i++) {
+ uint32_t mask = (1U << i);
+ if ((dma.allocated_mask & mask) == 0U) {
+ const stm32_dma_stream_t *dmastp = STM32_DMA_STREAM(i);
+
+ /* Installs the DMA handler.*/
+ dma.streams[i].func = func;
+ dma.streams[i].param = param;
+ dma.allocated_mask |= mask;
+
+ /* Enabling DMA clocks required by the current streams set.*/
+ if ((STM32_DMA1_STREAMS_MASK & mask) != 0U) {
+ rccEnableDMA1(true);
+ }
+ if ((STM32_DMA2_STREAMS_MASK & mask) != 0U) {
+ rccEnableDMA2(true);
+ }
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccEnableDMAMUX)
+ /* Enabling DMAMUX if present.*/
+ if (dma.allocated_mask != 0U) {
+ rccEnableDMAMUX(true);
+ }
+#endif
+
+ /* Putting the stream in a safe state.*/
+ dmaStreamDisable(dmastp);
+ dmastp->stream->CR = STM32_DMA_CR_RESET_VALUE;
+ dmastp->stream->FCR = STM32_DMA_FCR_RESET_VALUE;
+
+ /* Enables the associated IRQ vector if a callback is defined.*/
+ if (func != NULL) {
+ nvicEnableVector(dmastp->vector, priority);
+ }
+
+ return dmastp;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Allocates a DMA stream.
+ * @details The stream is allocated and, if required, the DMA clock enabled.
+ * The function also enables the IRQ vector associated to the stream
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific stream or:
+ * - @p STM32_DMA_STREAM_ID_ANY for any stream.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream
+ * on DMA1.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream
+ * on DMA2.
+ * .
+ * @param[in] priority IRQ priority for the DMA stream
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_dma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
+ *
+ * @api
+ */
+const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param) {
+ const stm32_dma_stream_t *dmastp;
+
+ osalSysLock();
+ dmastp = dmaStreamAllocI(id, priority, func, param);
+ osalSysUnlock();
+
+ return dmastp;
+}
+
+/**
+ * @brief Releases a DMA stream.
+ * @details The stream is freed and, if required, the DMA clock disabled.
+ * Trying to release a unallocated stream is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @iclass
+ */
+void dmaStreamFreeI(const stm32_dma_stream_t *dmastp) {
+
+ osalDbgCheck(dmastp != NULL);
+
+ /* Check if the streams is not taken.*/
+ osalDbgAssert((dma.allocated_mask & (1U << dmastp->selfindex)) != 0U,
+ "not allocated");
+
+ /* Disables the associated IRQ vector.*/
+ nvicDisableVector(dmastp->vector);
+
+ /* Marks the stream as not allocated.*/
+ dma.allocated_mask &= ~(1U << dmastp->selfindex);
+
+ /* Shutting down clocks that are no more required, if any.*/
+ if ((dma.allocated_mask & STM32_DMA1_STREAMS_MASK) == 0U) {
+ rccDisableDMA1();
+ }
+ if ((dma.allocated_mask & STM32_DMA2_STREAMS_MASK) == 0U) {
+ rccDisableDMA2();
+ }
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && defined(rccDisableDMAMUX)
+ /* Shutting down DMAMUX if present.*/
+ if (dma.allocated_mask == 0U) {
+ rccDisableDMAMUX();
+ }
+#endif
+}
+
+/**
+ * @brief Releases a DMA stream.
+ * @details The stream is freed and, if required, the DMA clock disabled.
+ * Trying to release a unallocated stream is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @api
+ */
+void dmaStreamFree(const stm32_dma_stream_t *dmastp) {
+
+ osalSysLock();
+ dmaStreamFreeI(dmastp);
+ osalSysUnlock();
+}
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Associates a peripheral request to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ *
+ * @param[in] dmastp pointer to a @p stm32_dma_stream_t structure
+ * @param[in] per peripheral identifier
+ *
+ * @special
+ */
+void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per) {
+
+ osalDbgCheck(per < 256U);
+
+ dmastp->mux->CCR = per;
+}
+#endif
+
+#endif /* STM32_DMA_REQUIRED */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h new file mode 100644 index 0000000..2562039 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h @@ -0,0 +1,682 @@ +/*
+ ChibiOS - Copyright (C) 2006..2019 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 DMAv2/stm32_dma.h
+ * @brief Enhanced-DMA helper driver header.
+ *
+ * @addtogroup STM32_DMA
+ * @{
+ */
+
+#ifndef STM32_DMA_H
+#define STM32_DMA_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief DMA capability.
+ * @details if @p TRUE then the DMA is able of burst transfers, FIFOs,
+ * scatter gather and other advanced features.
+ */
+#define STM32_DMA_ADVANCED TRUE
+
+/**
+ * @brief Total number of DMA streams.
+ * @details This is the total number of streams among all the DMA units.
+ */
+#define STM32_DMA_STREAMS 16U
+
+/**
+ * @brief Mask of the ISR bits passed to the DMA callback functions.
+ */
+#define STM32_DMA_ISR_MASK 0x3DU
+
+/**
+ * @brief Returns the channel associated to the specified stream.
+ *
+ * @param[in] id the unique numeric stream identifier
+ * @param[in] c a stream/channel association word, one channel per
+ * nibble
+ * @return Returns the channel associated to the stream.
+ */
+#define STM32_DMA_GETCHANNEL(id, c) (((c) >> (((id) & 7U) * 4U)) & 15U)
+
+/**
+ * @brief Checks if a DMA priority is within the valid range.
+ * @param[in] prio DMA priority
+ *
+ * @retval The check result.
+ * @retval false invalid DMA priority.
+ * @retval true correct DMA priority.
+ */
+#define STM32_DMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U))
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == FALSE) || defined(_DOXYGEN__)
+/**
+ * @brief Checks if a DMA stream id is within the valid range.
+ *
+ * @param[in] id DMA stream id
+ * @retval The check result.
+ * @retval false invalid DMA stream.
+ * @retval true correct DMA stream.
+ */
+#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) <= STM32_DMA_STREAMS))
+#else /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */
+#if STM32_HAS_DMA2 == TRUE
+#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) <= (STM32_DMA_STREAMS + 2)))
+#else
+#define STM32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \
+ ((id) <= (STM32_DMA_STREAMS + 1)))
+#endif
+#endif /* STM32_DMA_SUPPORTS_DMAMUX == FALSE */
+
+/**
+ * @brief Returns an unique numeric identifier for a DMA stream.
+ *
+ * @param[in] dma the DMA unit number
+ * @param[in] stream the stream number
+ * @return An unique numeric stream identifier.
+ */
+#define STM32_DMA_STREAM_ID(dma, stream) ((((dma) - 1U) * 8U) + (stream))
+
+/**
+ * @brief Returns a DMA stream identifier mask.
+ *
+ *
+ * @param[in] dma the DMA unit number
+ * @param[in] stream the stream number
+ * @return A DMA stream identifier mask.
+ */
+#define STM32_DMA_STREAM_ID_MSK(dma, stream) \
+ (1U << STM32_DMA_STREAM_ID(dma, stream))
+
+/**
+ * @brief Checks if a DMA stream unique identifier belongs to a mask.
+ * @param[in] id the stream numeric identifier
+ * @param[in] mask the stream numeric identifiers mask
+ *
+ * @retval The check result.
+ * @retval false id does not belong to the mask.
+ * @retval true id belongs to the mask.
+ */
+#define STM32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask)))
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(_DOXYGEN__)
+/**
+ * @name Special stream identifiers
+ * @{
+ */
+#define STM32_DMA_STREAM_ID_ANY STM32_DMA_STREAMS
+#define STM32_DMA_STREAM_ID_ANY_DMA1 (STM32_DMA_STREAM_ID_ANY + 1)
+#if STM32_HAS_DMA2 == TRUE
+#define STM32_DMA_STREAM_ID_ANY_DMA2 (STM32_DMA_STREAM_ID_ANY_DMA1 + 1)
+#endif
+/** @} */
+#endif
+
+/**
+ * @name DMA streams identifiers
+ * @{
+ */
+/**
+ * @brief Returns a pointer to a stm32_dma_stream_t structure.
+ *
+ * @param[in] id the stream numeric identifier
+ * @return A pointer to the stm32_dma_stream_t constant structure
+ * associated to the DMA stream.
+ */
+#define STM32_DMA_STREAM(id) (&_stm32_dma_streams[id])
+
+#define STM32_DMA1_STREAM0 STM32_DMA_STREAM(0)
+#define STM32_DMA1_STREAM1 STM32_DMA_STREAM(1)
+#define STM32_DMA1_STREAM2 STM32_DMA_STREAM(2)
+#define STM32_DMA1_STREAM3 STM32_DMA_STREAM(3)
+#define STM32_DMA1_STREAM4 STM32_DMA_STREAM(4)
+#define STM32_DMA1_STREAM5 STM32_DMA_STREAM(5)
+#define STM32_DMA1_STREAM6 STM32_DMA_STREAM(6)
+#define STM32_DMA1_STREAM7 STM32_DMA_STREAM(7)
+#define STM32_DMA2_STREAM0 STM32_DMA_STREAM(8)
+#define STM32_DMA2_STREAM1 STM32_DMA_STREAM(9)
+#define STM32_DMA2_STREAM2 STM32_DMA_STREAM(10)
+#define STM32_DMA2_STREAM3 STM32_DMA_STREAM(11)
+#define STM32_DMA2_STREAM4 STM32_DMA_STREAM(12)
+#define STM32_DMA2_STREAM5 STM32_DMA_STREAM(13)
+#define STM32_DMA2_STREAM6 STM32_DMA_STREAM(14)
+#define STM32_DMA2_STREAM7 STM32_DMA_STREAM(15)
+/** @} */
+
+/**
+ * @name CR register constants common to all DMA types
+ * @{
+ */
+#define STM32_DMA_CR_RESET_VALUE 0x00000000U
+#define STM32_DMA_CR_EN DMA_SxCR_EN
+#define STM32_DMA_CR_TEIE DMA_SxCR_TEIE
+#define STM32_DMA_CR_HTIE DMA_SxCR_HTIE
+#define STM32_DMA_CR_TCIE DMA_SxCR_TCIE
+#define STM32_DMA_CR_PFCTRL DMA_SxCR_PFCTRL
+#define STM32_DMA_CR_DIR_MASK DMA_SxCR_DIR
+#define STM32_DMA_CR_DIR_P2M 0
+#define STM32_DMA_CR_DIR_M2P DMA_SxCR_DIR_0
+#define STM32_DMA_CR_DIR_M2M DMA_SxCR_DIR_1
+#define STM32_DMA_CR_CIRC DMA_SxCR_CIRC
+#define STM32_DMA_CR_PINC DMA_SxCR_PINC
+#define STM32_DMA_CR_MINC DMA_SxCR_MINC
+#define STM32_DMA_CR_PSIZE_MASK DMA_SxCR_PSIZE
+#define STM32_DMA_CR_PSIZE_BYTE 0
+#define STM32_DMA_CR_PSIZE_HWORD DMA_SxCR_PSIZE_0
+#define STM32_DMA_CR_PSIZE_WORD DMA_SxCR_PSIZE_1
+#define STM32_DMA_CR_MSIZE_MASK DMA_SxCR_MSIZE
+#define STM32_DMA_CR_MSIZE_BYTE 0
+#define STM32_DMA_CR_MSIZE_HWORD DMA_SxCR_MSIZE_0
+#define STM32_DMA_CR_MSIZE_WORD DMA_SxCR_MSIZE_1
+#define STM32_DMA_CR_SIZE_MASK (STM32_DMA_CR_PSIZE_MASK | \
+ STM32_DMA_CR_MSIZE_MASK)
+#define STM32_DMA_CR_PL_MASK DMA_SxCR_PL
+#define STM32_DMA_CR_PL(n) ((n) << 16U)
+/** @} */
+
+/**
+ * @name CR register constants only found in DMAv2
+ * @{
+ */
+#define STM32_DMA_CR_DMEIE DMA_SxCR_DMEIE
+#define STM32_DMA_CR_PFCTRL DMA_SxCR_PFCTRL
+#define STM32_DMA_CR_PINCOS DMA_SxCR_PINCOS
+#define STM32_DMA_CR_DBM DMA_SxCR_DBM
+#define STM32_DMA_CR_CT DMA_SxCR_CT
+#define STM32_DMA_CR_PBURST_MASK DMA_SxCR_PBURST
+#define STM32_DMA_CR_PBURST_SINGLE 0U
+#define STM32_DMA_CR_PBURST_INCR4 DMA_SxCR_PBURST_0
+#define STM32_DMA_CR_PBURST_INCR8 DMA_SxCR_PBURST_1
+#define STM32_DMA_CR_PBURST_INCR16 (DMA_SxCR_PBURST_0 | DMA_SxCR_PBURST_1)
+#define STM32_DMA_CR_MBURST_MASK DMA_SxCR_MBURST
+#define STM32_DMA_CR_MBURST_SINGLE 0U
+#define STM32_DMA_CR_MBURST_INCR4 DMA_SxCR_MBURST_0
+#define STM32_DMA_CR_MBURST_INCR8 DMA_SxCR_MBURST_1
+#define STM32_DMA_CR_MBURST_INCR16 (DMA_SxCR_MBURST_0 | DMA_SxCR_MBURST_1)
+#if (STM32_DMA_SUPPORTS_DMAMUX == FALSE) || defined(__DOXYGEN__)
+#define STM32_DMA_CR_CHSEL_MASK DMA_SxCR_CHSEL
+#define STM32_DMA_CR_CHSEL(n) ((n) << 25U)
+#else
+#define STM32_DMA_CR_CHSEL_MASK 0U
+#define STM32_DMA_CR_CHSEL(n) 0U
+#endif
+/** @} */
+
+/**
+ * @name FCR register constants only found in DMAv2
+ * @{
+ */
+#define STM32_DMA_FCR_RESET_VALUE 0x00000021U
+#define STM32_DMA_FCR_FEIE DMA_SxFCR_FEIE
+#define STM32_DMA_FCR_FS_MASK DMA_SxFCR_FS
+#define STM32_DMA_FCR_DMDIS DMA_SxFCR_DMDIS
+#define STM32_DMA_FCR_FTH_MASK DMA_SxFCR_FTH
+#define STM32_DMA_FCR_FTH_1Q 0
+#define STM32_DMA_FCR_FTH_HALF DMA_SxFCR_FTH_0
+#define STM32_DMA_FCR_FTH_3Q DMA_SxFCR_FTH_1
+#define STM32_DMA_FCR_FTH_FULL (DMA_SxFCR_FTH_0 | DMA_SxFCR_FTH_1)
+/** @} */
+
+/**
+ * @name Status flags passed to the ISR callbacks
+ */
+#define STM32_DMA_ISR_FEIF DMA_LISR_FEIF0
+#define STM32_DMA_ISR_DMEIF DMA_LISR_DMEIF0
+#define STM32_DMA_ISR_TEIF DMA_LISR_TEIF0
+#define STM32_DMA_ISR_HTIF DMA_LISR_HTIF0
+#define STM32_DMA_ISR_TCIF DMA_LISR_TCIF0
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_DMA_SUPPORTS_DMAMUX)
+#error "STM32_DMA_SUPPORTS_DMAMUX not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_DMA1)
+#error "STM32_HAS_DMA1 missing in registry"
+#endif
+
+#if !defined(STM32_HAS_DMA2)
+#error "STM32_HAS_DMA2 missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH0_HANDLER)
+#error "STM32_DMA1_CH0_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH1_HANDLER)
+#error "STM32_DMA1_CH1_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH2_HANDLER)
+#error "STM32_DMA1_CH2_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH3_HANDLER)
+#error "STM32_DMA1_CH3_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH4_HANDLER)
+#error "STM32_DMA1_CH4_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH5_HANDLER)
+#error "STM32_DMA1_CH5_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH6_HANDLER)
+#error "STM32_DMA1_CH6_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH7_HANDLER)
+#error "STM32_DMA1_CH7_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH0_HANDLER)
+#error "STM32_DMA2_CH0_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH1_HANDLER)
+#error "STM32_DMA2_CH1_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH2_HANDLER)
+#error "STM32_DMA2_CH2_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH3_HANDLER)
+#error "STM32_DMA2_CH3_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH4_HANDLER)
+#error "STM32_DMA2_CH4_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH5_HANDLER)
+#error "STM32_DMA2_CH5_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH6_HANDLER)
+#error "STM32_DMA2_CH6_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH7_HANDLER)
+#error "STM32_DMA2_CH7_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH0_NUMBER)
+#error "STM32_DMA1_CH0_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH1_NUMBER)
+#error "STM32_DMA1_CH1_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH2_NUMBER)
+#error "STM32_DMA1_CH2_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH3_NUMBER)
+#error "STM32_DMA1_CH3_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH4_NUMBER)
+#error "STM32_DMA1_CH4_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH5_NUMBER)
+#error "STM32_DMA1_CH5_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH6_NUMBER)
+#error "STM32_DMA1_CH6_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA1_CH7_NUMBER)
+#error "STM32_DMA1_CH7_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH0_NUMBER)
+#error "STM32_DMA2_CH0_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH1_NUMBER)
+#error "STM32_DMA2_CH1_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH2_NUMBER)
+#error "STM32_DMA2_CH2_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH3_NUMBER)
+#error "STM32_DMA2_CH3_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH4_NUMBER)
+#error "STM32_DMA2_CH4_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH5_NUMBER)
+#error "STM32_DMA2_CH5_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH6_NUMBER)
+#error "STM32_DMA2_CH6_NUMBER missing in registry"
+#endif
+
+#if !defined(STM32_DMA2_CH7_NUMBER)
+#error "STM32_DMA2_CH7_NUMBER missing in registry"
+#endif
+
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+#include "stm32_dmamux.h"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 DMA ISR function type.
+ *
+ * @param[in] p parameter for the registered function
+ * @param[in] flags pre-shifted content of the xISR register, the bits
+ * are aligned to bit zero
+ */
+typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags);
+
+/**
+ * @brief STM32 DMA stream descriptor structure.
+ */
+typedef struct {
+ DMA_Stream_TypeDef *stream; /**< @brief Associated DMA stream. */
+ volatile uint32_t *ifcr; /**< @brief Associated IFCR reg. */
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+ DMAMUX_Channel_TypeDef *mux; /**< @brief Associated DMA mux. */
+#else
+ uint8_t dummy; /**< @brief Filler. */
+#endif
+ uint8_t shift; /**< @brief Bits offset in xIFCR
+ register. */
+ uint8_t selfindex; /**< @brief Index to self in array. */
+ uint8_t vector; /**< @brief Associated IRQ vector. */
+} stm32_dma_stream_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Associates a peripheral data register to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] addr value to be written in the PAR register
+ *
+ * @special
+ */
+#define dmaStreamSetPeripheral(dmastp, addr) { \
+ (dmastp)->stream->PAR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Associates a memory destination to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] addr value to be written in the M0AR register
+ *
+ * @special
+ */
+#define dmaStreamSetMemory0(dmastp, addr) { \
+ (dmastp)->stream->M0AR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Associates an alternate memory destination to a DMA stream.
+ * @note This function can be invoked in both ISR or thread context.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] addr value to be written in the M1AR register
+ *
+ * @special
+ */
+#define dmaStreamSetMemory1(dmastp, addr) { \
+ (dmastp)->stream->M1AR = (uint32_t)(addr); \
+}
+
+/**
+ * @brief Sets the number of transfers to be performed.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] size value to be written in the CNDTR register
+ *
+ * @special
+ */
+#define dmaStreamSetTransactionSize(dmastp, size) { \
+ (dmastp)->stream->NDTR = (uint32_t)(size); \
+}
+
+/**
+ * @brief Returns the number of transfers to be performed.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @return The number of transfers to be performed.
+ *
+ * @special
+ */
+#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->stream->NDTR))
+
+/**
+ * @brief Programs the stream mode settings.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] mode value to be written in the CR register
+ *
+ * @special
+ */
+#define dmaStreamSetMode(dmastp, mode) { \
+ (dmastp)->stream->CR = (uint32_t)(mode); \
+}
+
+/**
+ * @brief Programs the stream FIFO settings.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] mode value to be written in the FCR register
+ *
+ * @special
+ */
+#define dmaStreamSetFIFO(dmastp, mode) { \
+ (dmastp)->stream->FCR = (uint32_t)(mode); \
+}
+
+/**
+ * @brief DMA stream enable.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+#define dmaStreamEnable(dmastp) { \
+ (dmastp)->stream->CR |= STM32_DMA_CR_EN; \
+}
+
+/**
+ * @brief DMA stream disable.
+ * @details The function disables the specified stream, waits for the disable
+ * operation to complete and then clears any pending interrupt.
+ * @note This function can be invoked in both ISR or thread context.
+ * @note Interrupts enabling flags are set to zero after this call, see
+ * bug 3607518.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+#define dmaStreamDisable(dmastp) { \
+ (dmastp)->stream->CR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_DMEIE | \
+ STM32_DMA_CR_EN); \
+ while (((dmastp)->stream->CR & STM32_DMA_CR_EN) != 0) \
+ ; \
+ dmaStreamClearInterrupt(dmastp); \
+}
+
+/**
+ * @brief DMA stream interrupt sources clear.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+#define dmaStreamClearInterrupt(dmastp) { \
+ *(dmastp)->ifcr = STM32_DMA_ISR_MASK << (dmastp)->shift; \
+}
+
+/**
+ * @brief Starts a memory to memory operation using the specified stream.
+ * @note The default transfer data mode is "byte to byte" but it can be
+ * changed by specifying extra options in the @p mode parameter.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @param[in] mode value to be written in the CCR register, this value
+ * is implicitly ORed with:
+ * - @p STM32_DMA_CR_MINC
+ * - @p STM32_DMA_CR_PINC
+ * - @p STM32_DMA_CR_DIR_M2M
+ * - @p STM32_DMA_CR_EN
+ * .
+ * @param[in] src source address
+ * @param[in] dst destination address
+ * @param[in] n number of data units to copy
+ */
+#define dmaStartMemCopy(dmastp, mode, src, dst, n) { \
+ dmaStreamSetPeripheral(dmastp, src); \
+ dmaStreamSetMemory0(dmastp, dst); \
+ dmaStreamSetTransactionSize(dmastp, n); \
+ dmaStreamSetMode(dmastp, (mode) | \
+ STM32_DMA_CR_MINC | STM32_DMA_CR_PINC | \
+ STM32_DMA_CR_DIR_M2M); \
+ dmaStreamEnable(dmastp); \
+}
+
+/**
+ * @brief Polled wait for DMA transfer end.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ */
+#define dmaWaitCompletion(dmastp) { \
+ (dmastp)->stream->CR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_DMEIE); \
+ while ((dmastp)->stream->CR & STM32_DMA_CR_EN) \
+ ; \
+ dmaStreamClearInterrupt(dmastp); \
+}
+
+/**
+ * @brief DMA stream current target.
+ * @note This function can be invoked in both ISR or thread context.
+ * @pre The stream must have been allocated using @p dmaStreamAlloc().
+ * @post After use the stream can be released using @p dmaStreamFree().
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ * @return Current memory target index.
+ *
+ * @special
+ */
+#define dmaStreamGetCurrentTarget(dmastp) \
+ (((dmastp)->stream->CR >> DMA_SxCR_CT_Pos) & 1U)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void dmaInit(void);
+ const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param);
+ const stm32_dma_stream_t *dmaStreamAlloc(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param);
+ void dmaStreamFreeI(const stm32_dma_stream_t *dmastp);
+ void dmaStreamFree(const stm32_dma_stream_t *dmastp);
+#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
+ void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_DMA_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk new file mode 100644 index 0000000..63016f9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt new file mode 100644 index 0000000..ac83cf5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/notes.txt @@ -0,0 +1,14 @@ +STM32 EXTIv1 driver.
+
+Driver capability:
+
+- Support for the EXTI peripheral.
+
+The file registry must export:
+
+STM32_EXTI_NUM_LINES - Number of EXTI lines, it can be between 0 and 63.
+STM32_EXTI_IMR1_MASK - Mask of the fixed lines that must not be
+ handled by the driver (0..31).
+STM32_EXTI_IMR2_MASK - Mask of the fixed lines that must not be
+ handled by the driver (32..63). Only required
+ if STM32_EXTI_NUM_LINES is greater than 32.
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c new file mode 100644 index 0000000..e2877cf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.c @@ -0,0 +1,216 @@ +/*
+ 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 EXTIv1/stm32_exti.c
+ * @brief EXTI helper driver code.
+ *
+ * @addtogroup STM32_EXTI
+ * @details EXTI sharing helper driver.
+ * @{
+ */
+
+#include "hal.h"
+
+/* The following macro is only defined if some driver requiring EXTI services
+ has been enabled.*/
+#if defined(STM32_EXTI_REQUIRED) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 EXTI group 1 lines initialization.
+ *
+ * @param[in] mask mask of group 1 lines to be initialized
+ * @param[in] mode initialization mode
+ *
+ * @api
+ */
+void extiEnableGroup1(uint32_t mask, extimode_t mode) {
+
+ /* Masked out lines must not be touched by this driver.*/
+ osalDbgAssert((mask & STM32_EXTI_IMR1_MASK) == 0U, "fixed lines");
+
+ if ((mode & EXTI_MODE_EDGES_MASK) == 0U) {
+ /* Disabling channels.*/
+ EXTI->IMR1 &= ~mask;
+ EXTI->EMR1 &= ~mask;
+ EXTI->RTSR1 &= ~mask;
+ EXTI->FTSR1 &= ~mask;
+#if STM32_EXTI_SEPARATE_RF == FALSE
+ EXTI->PR1 = mask;
+#else
+ EXTI->RPR1 = mask;
+ EXTI->FPR1 = mask;
+#endif
+ }
+ else {
+ /* Programming edge registers.*/
+ if (mode & EXTI_MODE_RISING_EDGE) {
+ EXTI->RTSR1 |= mask;
+ }
+ else {
+ EXTI->RTSR1 &= ~mask;
+ }
+ if (mode & EXTI_MODE_FALLING_EDGE) {
+ EXTI->FTSR1 |= mask;
+ }
+ else {
+ EXTI->FTSR1 &= ~mask;
+ }
+
+ /* Programming interrupt and event registers.*/
+ if ((mode & EXTI_MODE_ACTION_MASK) == EXTI_MODE_ACTION_INTERRUPT) {
+ EXTI->IMR1 |= mask;
+ EXTI->EMR1 &= ~mask;
+ }
+ else {
+ EXTI->EMR1 |= mask;
+ EXTI->IMR1 &= ~mask;
+ }
+ }
+}
+
+#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief STM32 EXTI group 2 lines initialization.
+ *
+ * @param[in] mask mask of group 2 lines to be initialized
+ * @param[in] mode initialization mode
+ *
+ * @api
+ */
+void extiEnableGroup2(uint32_t mask, extimode_t mode) {
+
+ /* Masked out lines must not be touched by this driver.*/
+ osalDbgAssert((mask & STM32_EXTI_IMR2_MASK) == 0U, "fixed lines");
+
+ if ((mode & EXTI_MODE_EDGES_MASK) == 0U) {
+ /* Disabling channels.*/
+ EXTI->IMR2 &= ~mask;
+ EXTI->EMR2 &= ~mask;
+ EXTI->RTSR2 &= ~mask;
+ EXTI->FTSR2 &= ~mask;
+#if STM32_EXTI_SEPARATE_RF == FALSE
+ EXTI->PR2 = mask;
+#else
+ EXTI->RPR2 = mask;
+ EXTI->FPR2 = mask;
+#endif
+ }
+ else {
+ /* Programming edge registers.*/
+ if (mode & EXTI_MODE_RISING_EDGE) {
+ EXTI->RTSR2 |= mask;
+ }
+ else {
+ EXTI->RTSR2 &= ~mask;
+ }
+ if (mode & EXTI_MODE_FALLING_EDGE) {
+ EXTI->FTSR2 |= mask;
+ }
+ else {
+ EXTI->FTSR2 &= ~mask;
+ }
+
+ /* Programming interrupt and event registers.*/
+ if ((mode & EXTI_MODE_ACTION_MASK) == EXTI_MODE_ACTION_INTERRUPT) {
+ EXTI->IMR2 |= mask;
+ EXTI->EMR2 &= ~mask;
+ }
+ else {
+ EXTI->EMR2 |= mask;
+ EXTI->IMR2 &= ~mask;
+ }
+ }
+}
+#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */
+
+/**
+ * @brief STM32 EXTI line initialization.
+ *
+ * @param[in] line line to be initialized
+ * @param[in] mode initialization mode
+ *
+ * @api
+ */
+void extiEnableLine(extiline_t line, extimode_t mode) {
+ uint32_t mask = (1U << (line & 0x1FU));
+
+ osalDbgCheck(line < STM32_EXTI_NUM_LINES);
+ osalDbgCheck((mode & ~EXTI_MODE_MASK) == 0U);
+
+#if STM32_EXTI_HAS_GROUP2 == TRUE
+ if (line < 32) {
+#endif
+ extiEnableGroup1(mask, mode);
+#if STM32_EXTI_HAS_GROUP2 == TRUE
+ }
+ else {
+ extiEnableGroup2(mask, mode);
+ }
+#endif
+}
+
+/**
+ * @brief STM32 EXTI line IRQ status clearing.
+ *
+ * @param[in] line line to be initialized
+ *
+ * @api
+ */
+void extiClearLine(extiline_t line) {
+ uint32_t mask = (1U << (line & 0x1FU));
+
+ osalDbgCheck(line < STM32_EXTI_NUM_LINES);
+
+#if STM32_EXTI_HAS_GROUP2 == TRUE
+ if (line < 32) {
+#endif
+ extiClearGroup1(mask);
+#if STM32_EXTI_HAS_GROUP2 == TRUE
+ }
+ else {
+ extiClearGroup2(mask);
+ }
+#endif
+}
+
+#endif /* STM32_EXTI_REQUIRED */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h new file mode 100644 index 0000000..dadc58c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti.h @@ -0,0 +1,257 @@ +/*
+ 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 EXTIv1/stm32_exti.h
+ * @brief EXTI helper driver header.
+ *
+ * @addtogroup STM32_EXTI
+ * @{
+ */
+
+#ifndef STM32_EXTI_H
+#define STM32_EXTI_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name EXTI channel modes
+ * @{
+ */
+#define EXTI_MODE_MASK 7U /**< @brief Mode parameter mask. */
+#define EXTI_MODE_EDGES_MASK 3U /**< @brief Edges field mask. */
+#define EXTI_MODE_DISABLED 0U /**< @brief Channel disabled. */
+#define EXTI_MODE_RISING_EDGE 1U /**< @brief Rising edge callback. */
+#define EXTI_MODE_FALLING_EDGE 2U /**< @brief Falling edge callback. */
+#define EXTI_MODE_BOTH_EDGES 3U /**< @brief Both edges callback. */
+#define EXTI_MODE_ACTION_MASK 4U /**< @brief Action field mask. */
+#define EXTI_MODE_ACTION_INTERRUPT 0U /**< @brief Interrupt mode. */
+#define EXTI_MODE_ACTION_EVENT 4U /**< @brief Event mode. */
+/** @} */
+
+/* Handling differences in ST headers.*/
+#if !defined(STM32H7XX) && !defined(STM32L4XX) && !defined(STM32L4XXP) && \
+ !defined(STM32G0XX) && !defined(STM32G4XX)
+#define EMR1 EMR
+#define IMR1 IMR
+#define PR1 PR
+#define RTSR1 RTSR
+#define FTSR1 FTSR
+#endif
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_EXTI_NUM_LINES)
+#error "STM32_EXTI_NUM_LINES not defined in registry"
+#endif
+
+/* Checking for presence of bank 2 registers. If the definition is not
+ present in registry then it is inferred by the number of channels (which
+ is not an always-good method, see G0.*/
+#if !defined(STM32_EXTI_HAS_GROUP2)
+#if STM32_EXTI_NUM_LINES <= 32
+#define STM32_EXTI_HAS_GROUP2 FALSE
+#else
+#define STM32_EXTI_HAS_GROUP2 TRUE
+#endif
+#endif /* !defined(STM32_EXTI_HAS_GROUP2) */
+
+/* Determines if EXTI has dedicated CR register or if it is done in
+ SYSCFG (old style).*/
+#if !defined(STM32_EXTI_HAS_CR)
+#define STM32_EXTI_HAS_CR FALSE
+#endif
+
+/* Determines if EXTI has dedicated separate registers for raising and
+ falling edges.*/
+#if !defined(STM32_EXTI_SEPARATE_RF)
+#define STM32_EXTI_SEPARATE_RF FALSE
+#endif
+
+#if (STM32_EXTI_NUM_LINES < 0) || (STM32_EXTI_NUM_LINES > 63)
+#error "invalid STM32_EXTI_NUM_LINES value"
+#endif
+
+#if !defined(STM32_EXTI_IMR1_MASK)
+#error "STM32_EXTI_IMR1_MASK not defined in registry"
+#endif
+
+#if STM32_EXTI_NUM_LINES > 32
+#if !defined(STM32_EXTI_IMR2_MASK)
+#error "STM32_EXTI_IMR2_MASK not defined in registry"
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of an EXTI line identifier.
+ */
+typedef uint32_t extiline_t;
+
+/**
+ * @brief Type of an EXTI line mode.
+ */
+typedef uint32_t extimode_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief From group 1 line number to mask.
+ *
+ * @param[in] line line number in range 0..31
+ */
+#define EXTI_MASK1(line) (uint32_t)(1U << (line))
+
+/**
+ * @brief From group 2 line number to mask.
+ *
+ * @param[in] line line number in range 32..63
+ */
+#define EXTI_MASK2(line) (uint32_t)(1U << ((line) - 32U))
+
+/**
+ * @brief STM32 EXTI group 1 IRQ status clearing.
+ *
+ * @param[in] mask mask of group 1 lines to be initialized
+ *
+ * @special
+ */
+#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__)
+#define extiClearGroup1(mask) do { \
+ osalDbgAssert(((mask) & STM32_EXTI_IMR1_MASK) == 0U, "fixed lines"); \
+ EXTI->PR1 = (uint32_t)(mask); \
+} while (false)
+#else
+#define extiClearGroup1(mask) do { \
+ osalDbgAssert(((mask) & STM32_EXTI_IMR1_MASK) == 0U, "fixed lines"); \
+ EXTI->RPR1 = (uint32_t)(mask); \
+ EXTI->FPR1 = (uint32_t)(mask); \
+} while (false)
+#endif
+
+#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief STM32 EXTI group 2 IRQ status clearing.
+ *
+ * @param[in] mask mask of group 2 lines to be initialized
+ *
+ * @special
+ */
+#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__)
+#define extiClearGroup2(mask) do { \
+ osalDbgAssert(((mask) & STM32_EXTI_IMR2_MASK) == 0U, "fixed lines"); \
+ EXTI->PR2 = (uint32_t)(mask); \
+} while (false)
+#else
+#define extiClearGroup2(mask) do { \
+ osalDbgAssert(((mask) & STM32_EXTI_IMR2_MASK) == 0U, "fixed lines"); \
+ EXTI->RPR2 = (uint32_t)(mask); \
+ EXTI->FPR2 = (uint32_t)(mask); \
+} while (false)
+#endif
+#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */
+
+/**
+ * @brief Serves an EXTI interrupt in group 1.
+ *
+ * @param[in] mask mask of lines to be cleared
+ * @param[out] out mask of lines needing processing
+ *
+ * @special
+ */
+#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__)
+#define extiGetAndClearGroup1(mask, out) do { \
+ uint32_t pr1; \
+ \
+ pr1 = EXTI->PR1 & (mask); \
+ (out) = pr1; \
+ EXTI->PR1 = pr1; \
+} while (false)
+#else
+#define extiGetAndClearGroup1(mask, out) do { \
+ uint32_t rpr1, fpr1; \
+ \
+ rpr1 = EXTI->RPR1 & (mask); \
+ fpr1 = EXTI->FPR1 & (mask); \
+ (out) = rpr1 | fpr1; \
+ EXTI->RPR1 = rpr1; \
+ EXTI->FPR1 = fpr1; \
+} while (false)
+#endif
+
+#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Serves an EXTI interrupt in group 2.
+ *
+ * @param[in] mask mask of lines to be cleared
+ * @param[out] out mask of lines needing processing
+ *
+ * @special
+ */
+#if (STM32_EXTI_SEPARATE_RF == FALSE) || defined(__DOXYGEN__)
+#define extiGetAndClearGroup2(mask, out) do { \
+ uint32_t pr2; \
+ \
+ pr2 = EXTI->PR2 & (mask); \
+ (out) = pr2; \
+ EXTI->PR2 = pr2; \
+} while (false)
+#else
+#define extiGetAndClearGroup2(mask, out) do { \
+ uint32_t rpr2, fpr2; \
+ \
+ rpr2 = EXTI->RPR2 & (mask); \
+ fpr2 = EXTI->FPR2 & (mask); \
+ (out) = rpr2 | fpr2; \
+ EXTI->RPR2 = rpr2; \
+ EXTI->FPR2 = fpr2; \
+} while (false)
+#endif
+#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void extiEnableGroup1(uint32_t mask, extimode_t mode);
+#if (STM32_EXTI_HAS_GROUP2 == TRUE) || defined(__DOXYGEN__)
+ void extiEnableGroup2(uint32_t mask, extimode_t mode);
+#endif /* STM32_EXTI_HAS_GROUP2 == TRUE */
+ void extiEnableLine(extiline_t line, extimode_t mode);
+ void extiClearLine(extiline_t line);
+ #ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_EXTI_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc new file mode 100644 index 0000000..e02707b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0.inc @@ -0,0 +1,95 @@ +/* + 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 EXTIv1/stm32_exti0.inc + * @brief Shared EXTI0 handler. + * + * @addtogroup STM32_EXTI0_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI0_PRIORITY) +#error "STM32_IRQ_EXTI0_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI0_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI0_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti0_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI0_NUMBER, STM32_IRQ_EXTI0_PRIORITY); +#endif +} + +static inline void exti0_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI0_HANDLER) +/** + * @brief EXTI[0] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI0_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 0, pr); + + exti_serve_irq(pr, 0); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc new file mode 100644 index 0000000..d20141b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti0_1.inc @@ -0,0 +1,96 @@ +/* + 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 EXTIv1/stm32_exti0_1.inc + * @brief Shared EXTI0_1 handler. + * + * @addtogroup STM32_EXTI0_1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI0_1_PRIORITY) +#error "STM32_IRQ_EXTI0_1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI0_1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI0_1_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti0_1_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI0_1_NUMBER, STM32_IRQ_EXTI0_1_PRIORITY); +#endif +} + +static inline void exti0_1_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI0_1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI0_1_HANDLER) +/** + * @brief EXTI[0], EXTI[1] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI0_1_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 0) | (1U << 1), pr); + + exti_serve_irq(pr, 0); + exti_serve_irq(pr, 1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc new file mode 100644 index 0000000..c7a9de1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti1.inc @@ -0,0 +1,95 @@ +/* + 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 EXTIv1/stm32_exti1.inc + * @brief Shared EXTI1 handler. + * + * @addtogroup STM32_EXTI1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI1_PRIORITY) +#error "STM32_IRQ_EXTI1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI1_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti1_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI1_NUMBER, STM32_IRQ_EXTI1_PRIORITY); +#endif +} + +static inline void exti1_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI1_HANDLER) +/** + * @brief EXTI[1] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI1_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 1, pr); + + exti_serve_irq(pr, 1); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc new file mode 100644 index 0000000..3288dc9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti10_15.inc @@ -0,0 +1,101 @@ +/* + 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 EXTIv1/stm32_exti10_15.inc + * @brief Shared EXTI10_15 handler. + * + * @addtogroup STM32_EXTI10_15_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI10_15_PRIORITY) +#error "STM32_IRQ_EXTI10_15_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI10_15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI10_15_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti10_15_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI10_15_NUMBER, STM32_IRQ_EXTI10_15_PRIORITY); +#endif +} + +static inline void exti10_15_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI10_15_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI10_15_HANDLER) +/** + * @brief EXTI[10]..EXTI[15] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI10_15_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 10) | (1U << 11) | (1U << 12) | (1U << 13) | + (1U << 14) | (1U << 15), pr); + + exti_serve_irq(pr, 10); + exti_serve_irq(pr, 11); + exti_serve_irq(pr, 12); + exti_serve_irq(pr, 13); + exti_serve_irq(pr, 14); + exti_serve_irq(pr, 15); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc new file mode 100644 index 0000000..aa21235 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-35_38.inc @@ -0,0 +1,130 @@ +/* + 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 EXTIv1/stm32_exti16-35_38.inc + * @brief Shared EXTI16-35_38 handler. + * + * @addtogroup STM32_EXTI1635_38_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI1635_38_PRIORITY) +#error "STM32_IRQ_EXTI1635_38_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI1635_38_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI1635_38_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti16_exti35_38_irq_init(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI35_IS_USED) || \ + defined(STM32_EXTI36_IS_USED) || defined(STM32_EXTI37_IS_USED) || \ + defined(STM32_EXTI38_IS_USED) + nvicEnableVector(STM32_EXTI1635_38_NUMBER, STM32_IRQ_EXTI1635_38_PRIORITY); +#endif +} + +static inline void exti16_exti35_38_irq_deinit(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI35_IS_USED) || \ + defined(STM32_EXTI36_IS_USED) || defined(STM32_EXTI37_IS_USED) || \ + defined(STM32_EXTI38_IS_USED) + nvicDisableVector(STM32_EXTI1635_38_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI35_IS_USED) || \ + defined(STM32_EXTI36_IS_USED) || defined(STM32_EXTI37_IS_USED) || \ + defined(STM32_EXTI38_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI1635_38_HANDLER) +/** + * @brief EXTI[16], EXTI[35], EXTI[38] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI163538_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + +#if defined(STM32_EXTI16_IS_USED) + extiGetAndClearGroup1(1U << 16, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI16_ISR) + STM32_EXTI16_ISR(pr, 16); +#endif +#endif + +#if defined(STM32_EXTI35_IS_USED) || defined(STM32_EXTI36_IS_USED) || \ + defined(STM32_EXTI37_IS_USED) || defined(STM32_EXTI38_IS_USED) + extiGetAndClearGroup2((1U << (35 - 32)) | (1U << (36 - 32)) | + (1U << (37 - 32)) | (1U << (38 - 32)), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI35_ISR) + STM32_EXTI35_ISR(pr, 35); +#endif +#if defined(STM32_EXTI36_ISR) + STM32_EXTI35_ISR(pr, 36); +#endif +#if defined(STM32_EXTI37_ISR) + STM32_EXTI35_ISR(pr, 37); +#endif +#if defined(STM32_EXTI38_ISR) + STM32_EXTI38_ISR(pr, 38); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc new file mode 100644 index 0000000..b8aebe4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16-40_41.inc @@ -0,0 +1,119 @@ +/* + 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 EXTIv1/stm32_exti16-40_41.inc + * @brief Shared EXTI16-40_41 handler. + * + * @addtogroup STM32_EXTI164041_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI164041_PRIORITY) +#error "STM32_IRQ_EXTI164041_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI164041_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI164041_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti16_exti40_exti41_irq_init(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI40_IS_USED) || \ + defined(STM32_EXTI41_IS_USED) + nvicEnableVector(STM32_EXTI164041_NUMBER, STM32_IRQ_EXTI164041_PRIORITY); +#endif +} + +static inline void exti16_exti40_exti41_irq_deinit(void) { +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI40_IS_USED) || \ + defined(STM32_EXTI41_IS_USED) + nvicDisableVector(STM32_EXTI164041_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI16_IS_USED) || defined(STM32_EXTI40_IS_USED) || \ + defined(STM32_EXTI41_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI164041_HANDLER) +/** + * @brief EXTI[16], EXTI[40], EXTI[41] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI164041_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + +#if defined(STM32_EXTI16_IS_USED) + extiGetAndClearGroup1(1U << 16, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI16_ISR) + STM32_EXTI16_ISR(pr, 16); +#endif +#endif + +#if defined(STM32_EXTI40_IS_USED) || defined(STM32_EXTI41_IS_USED) + extiGetAndClearGroup2((1U << (40 - 32)) | (1U << (41 - 32)), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI40_ISR) + STM32_EXTI40_ISR(pr, 40); +#endif +#if defined(STM32_EXTI41_ISR) + STM32_EXTI41_ISR(pr, 41); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc new file mode 100644 index 0000000..d09ef3a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti16.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti16.inc + * @brief Shared EXTI16 handler. + * + * @addtogroup STM32_EXTI16_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI16_PRIORITY) +#error "STM32_IRQ_EXTI16_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI16_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI16_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti16_irq_init(void) { +#if defined(STM32_EXTI16_IS_USED) + nvicEnableVector(STM32_EXTI16_NUMBER, STM32_IRQ_EXTI16_PRIORITY); +#endif +} + +static inline void exti16_irq_deinit(void) { +#if defined(STM32_EXTI16_IS_USED) + nvicDisableVector(STM32_EXTI16_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI16_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI16_HANDLER) +/** + * @brief EXTI[16] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI16_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 16, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI16_ISR) + STM32_EXTI16_ISR(pr, 16); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc new file mode 100644 index 0000000..c2bbe0d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti17.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti17.inc + * @brief Shared EXTI17 handler. + * + * @addtogroup STM32_EXTI17_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI17_PRIORITY) +#error "STM32_IRQ_EXTI17_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI17_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI17_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti17_irq_init(void) { +#if defined(STM32_EXTI17_IS_USED) + nvicEnableVector(STM32_EXTI17_NUMBER, STM32_IRQ_EXTI17_PRIORITY); +#endif +} + +static inline void exti17_irq_deinit(void) { +#if defined(STM32_EXTI17_IS_USED) + nvicDisableVector(STM32_EXTI17_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI17_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI17_HANDLER) +/** + * @brief EXTI[17] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI17_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 17, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI17_ISR) + STM32_EXTI17_ISR(pr, 17); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc new file mode 100644 index 0000000..81e8290 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti18.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti18.inc + * @brief Shared EXTI18 handler. + * + * @addtogroup STM32_EXTI18_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI18_PRIORITY) +#error "STM32_IRQ_EXTI18_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI18_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI18_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti18_irq_init(void) { +#if defined(STM32_EXTI18_IS_USED) + nvicEnableVector(STM32_EXTI18_NUMBER, STM32_IRQ_EXTI18_PRIORITY); +#endif +} + +static inline void exti18_irq_deinit(void) { +#if defined(STM32_EXTI18_IS_USED) + nvicDisableVector(STM32_EXTI18_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI18_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI18_HANDLER) +/** + * @brief EXTI[18] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI18_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 18, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI18_ISR) + STM32_EXTI18_ISR(pr, 18); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc new file mode 100644 index 0000000..670fbdf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19-21.inc @@ -0,0 +1,104 @@ +/* + 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 EXTIv1/stm32_exti19-21.inc + * @brief Shared EXTI19-21 handler. + * + * @addtogroup STM32_EXTI1921_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI1921_PRIORITY) +#error "STM32_IRQ_EXTI1921_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI1921_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI1921_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti19_exti21_irq_init(void) { +#if defined(STM32_EXTI19_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicEnableVector(STM32_EXTI1921_NUMBER, STM32_IRQ_EXTI1921_PRIORITY); +#endif +} + +static inline void exti19_exti21_irq_deinit(void) { +#if defined(STM32_EXTI19_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicDisableVector(STM32_EXTI1921_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI19_IS_USED) || defined(STM32_EXTI21_IS_USED) || \ + defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI1921_HANDLER) +/** + * @brief EXTI[0], EXTI[1] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI1921_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 19) | (1U << 21), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI19_ISR) + STM32_EXTI16_ISR(pr, 19); +#endif +#if defined(STM32_EXTI21_ISR) + STM32_EXTI16_ISR(pr, 21); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc new file mode 100644 index 0000000..ef4b8f8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti19.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti19.inc + * @brief Shared EXTI19 handler. + * + * @addtogroup STM32_EXTI19_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI19_PRIORITY) +#error "STM32_IRQ_EXTI19_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI19_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI19_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti19_irq_init(void) { +#if defined(STM32_EXTI19_IS_USED) + nvicEnableVector(STM32_EXTI19_NUMBER, STM32_IRQ_EXTI19_PRIORITY); +#endif +} + +static inline void exti19_irq_deinit(void) { +#if defined(STM32_EXTI19_IS_USED) + nvicDisableVector(STM32_EXTI19_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI19_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI19_HANDLER) +/** + * @brief EXTI[19] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI19_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 19, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI19_ISR) + STM32_EXTI19_ISR(pr, 19); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc new file mode 100644 index 0000000..d5ddc40 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2.inc @@ -0,0 +1,95 @@ +/* + 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 EXTIv1/stm32_exti2.inc + * @brief Shared EXTI2 handler. + * + * @addtogroup STM32_EXTI2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI2_PRIORITY) +#error "STM32_IRQ_EXTI2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI2_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti2_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI2_NUMBER, STM32_IRQ_EXTI2_PRIORITY); +#endif +} + +static inline void exti2_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI2_HANDLER) +/** + * @brief EXTI[2] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI2_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 2, pr); + + exti_serve_irq(pr, 2); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc new file mode 100644 index 0000000..1d1b6af --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti20.inc + * @brief Shared EXTI20 handler. + * + * @addtogroup STM32_EXTI20_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI20_PRIORITY) +#error "STM32_IRQ_EXTI20_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI20_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI20_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti20_irq_init(void) { +#if defined(STM32_EXTI20_IS_USED) + nvicEnableVector(STM32_EXTI20_NUMBER, STM32_IRQ_EXTI20_PRIORITY); +#endif +} + +static inline void exti20_irq_deinit(void) { +#if defined(STM32_EXTI20_IS_USED) + nvicDisableVector(STM32_EXTI20_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI20_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI20_HANDLER) +/** + * @brief EXTI[20] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI20_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 20, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI20_ISR) + STM32_EXTI20_ISR(pr, 20); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc new file mode 100644 index 0000000..500f533 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti20_21.inc @@ -0,0 +1,104 @@ +/* + 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 EXTIv1/stm32_exti20_21.inc + * @brief Shared EXTI20_21 handler. + * + * @addtogroup STM32_EXTI20_21_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI20_21_PRIORITY) +#error "STM32_IRQ_EXTI20_21_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI20_21_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI20_21_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti20_exti21_irq_init(void) { +#if defined(STM32_EXTI20_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicEnableVector(STM32_EXTI20_21_NUMBER, STM32_IRQ_EXTI20_21_PRIORITY); +#endif +} + +static inline void exti20_exti21_irq_deinit(void) { +#if defined(STM32_EXTI20_IS_USED) || defined(STM32_EXTI21_IS_USED) + nvicDisableVector(STM32_EXTI20_21_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI20_IS_USED) || defined(STM32_EXTI21_IS_USED) || \ + defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI20_21_HANDLER) +/** + * @brief EXTI[20], EXTI[21] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI20_21_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 20) | (1U << 21), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI20_ISR) + STM32_EXTI20_ISR(pr, 20); +#endif +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc new file mode 100644 index 0000000..350091b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti21.inc + * @brief Shared EXTI21 handler. + * + * @addtogroup STM32_EXTI21_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI21_PRIORITY) +#error "STM32_IRQ_EXTI21_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI21_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI21_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti21_irq_init(void) { +#if defined(STM32_EXTI21_IS_USED) + nvicEnableVector(STM32_EXTI21_NUMBER, STM32_IRQ_EXTI21_PRIORITY); +#endif +} + +static inline void exti21_irq_deinit(void) { +#if defined(STM32_EXTI21_IS_USED) + nvicDisableVector(STM32_EXTI21_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI21_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI21_HANDLER) +/** + * @brief EXTI[21] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI21_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 21, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc new file mode 100644 index 0000000..95ea587 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22-29.inc @@ -0,0 +1,109 @@ +/* + 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 EXTIv1/stm32_exti21_22-29.inc + * @brief Shared EXTI21_22-29 handler. + * + * @addtogroup STM32_EXTI212229_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI212229_PRIORITY) +#error "STM32_IRQ_EXTI212229_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI212229_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI212229_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti21_exti22_exti29_irq_init(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(STM32_EXTI29_IS_USED) + nvicEnableVector(STM32_EXTI212229_NUMBER, STM32_IRQ_EXTI212229_PRIORITY); +#endif +} + +static inline void exti21_exti22_exti29_irq_deinit(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(STM32_EXTI29_IS_USED) + nvicDisableVector(STM32_EXTI212229_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(STM32_EXTI29_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI212229_HANDLER) +/** + * @brief EXTI[21], EXTI[22], EXTI[29] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI212229_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 21) | (1U << 22) | (1U << 29), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif +#if defined(STM32_EXTI22_ISR) + STM32_EXTI22_ISR(pr, 22); +#endif +#if defined(STM32_EXTI29_ISR) + STM32_EXTI29_ISR(pr, 29); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc new file mode 100644 index 0000000..973efd5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti21_22.inc @@ -0,0 +1,104 @@ +/* + 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 EXTIv1/stm32_exti21_22.inc + * @brief Shared EXTI21_22 handler. + * + * @addtogroup STM32_EXTI21_22_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI21_22_PRIORITY) +#error "STM32_IRQ_EXTI21_22_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI21_22_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI21_22_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti21_22_irq_init(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) + nvicEnableVector(STM32_EXTI21_22_NUMBER, STM32_IRQ_EXTI21_22_PRIORITY); +#endif +} + +static inline void exti21_22_irq_deinit(void) { +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) + nvicDisableVector(STM32_EXTI21_22_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI21_IS_USED) || defined(STM32_EXTI22_IS_USED) || \ + defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI21_22_HANDLER) +/** + * @brief EXTI[21], EXTI[22] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI21_22_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 21) | (1U << 22), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI21_ISR) + STM32_EXTI21_ISR(pr, 21); +#endif +#if defined(STM32_EXTI22_ISR) + STM32_EXTI22_ISR(pr, 22); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc new file mode 100644 index 0000000..e958615 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti22.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti22.inc + * @brief Shared EXTI22 handler. + * + * @addtogroup STM32_EXTI22_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI22_PRIORITY) +#error "STM32_IRQ_EXTI22_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI22_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI22_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti22_irq_init(void) { +#if defined(STM32_EXTI22_IS_USED) + nvicEnableVector(STM32_EXTI22_NUMBER, STM32_IRQ_EXTI22_PRIORITY); +#endif +} + +static inline void exti22_irq_deinit(void) { +#if defined(STM32_EXTI22_IS_USED) + nvicDisableVector(STM32_EXTI22_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI22_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI22_HANDLER) +/** + * @brief EXTI[22] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI22_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 22, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI22_ISR) + STM32_EXTI22_ISR(pr, 22); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc new file mode 100644 index 0000000..3180234 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti23.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti23.inc + * @brief Shared EXTI23 handler. + * + * @addtogroup STM32_EXTI23_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI23_PRIORITY) +#error "STM32_IRQ_EXTI23_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI23_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI23_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti23_irq_init(void) { +#if defined(STM32_EXTI23_IS_USED) + nvicEnableVector(STM32_EXTI23_NUMBER, STM32_IRQ_EXTI23_PRIORITY); +#endif +} + +static inline void exti23_irq_deinit(void) { +#if defined(STM32_EXTI23_IS_USED) + nvicDisableVector(STM32_EXTI23_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI23_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI23_HANDLER) +/** + * @brief EXTI[23] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI23_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 23, pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI23_ISR) + STM32_EXTI23_ISR(pr, 23); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc new file mode 100644 index 0000000..5c8ed9a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti2_3.inc @@ -0,0 +1,96 @@ +/* + 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 EXTIv1/stm32_exti2_3.inc + * @brief Shared EXTI2_3 handler. + * + * @addtogroup STM32_EXTI2_3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI2_3_PRIORITY) +#error "STM32_IRQ_EXTI2_3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI2_3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI2_3_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti2_3_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI2_3_NUMBER, STM32_IRQ_EXTI2_3_PRIORITY); +#endif +} + +static inline void exti2_3_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI2_3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI2_3_HANDLER) +/** + * @brief EXTI[2], EXTI[3] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI2_3_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 2) | (1U << 3), pr); + + exti_serve_irq(pr, 2); + exti_serve_irq(pr, 3); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc new file mode 100644 index 0000000..9c9be73 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti3.inc @@ -0,0 +1,95 @@ +/* + 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 EXTIv1/stm32_exti3.inc + * @brief Shared EXTI3 handler. + * + * @addtogroup STM32_EXTI3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI3_PRIORITY) +#error "STM32_IRQ_EXTI3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI3_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti3_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI3_NUMBER, STM32_IRQ_EXTI3_PRIORITY); +#endif +} + +static inline void exti3_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI3_HANDLER) +/** + * @brief EXTI[3] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI3_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 3, pr); + + exti_serve_irq(pr, 3); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc new file mode 100644 index 0000000..b8c1f41 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti30_32.inc @@ -0,0 +1,119 @@ +/* + 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 EXTIv1/stm32_exti30_32.inc + * @brief Shared EXTI30_32 handler. + * + * @addtogroup STM32_EXTI30_32_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI30_32_PRIORITY) +#error "STM32_IRQ_EXTI30_32_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI30_32_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI30_32_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti30_32_irq_init(void) { +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) || \ + defined(STM32_EXTI32_IS_USED) + nvicEnableVector(STM32_EXTI30_32_NUMBER, STM32_IRQ_EXTI30_32_PRIORITY); +#endif +} + +static inline void exti30_32_irq_deinit(void) { +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) || \ + defined(STM32_EXTI32_IS_USED) + nvicDisableVector(STM32_EXTI30_32_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) || \ + defined(STM32_EXTI32_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI30_32_HANDLER) +/** + * @brief EXTI[16], EXTI[40], EXTI[41] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI164041_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + +#if defined(STM32_EXTI30_IS_USED) || defined(STM32_EXTI31_IS_USED) + extiGetAndClearGroup1((1U << 30) | (1U << 31), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI30_ISR) + STM32_EXTI30_ISR(pr, 30); +#endif +#if defined(STM32_EXTI31_ISR) + STM32_EXTI31_ISR(pr, 31); +#endif +#endif + +#if defined(STM32_EXTI32_IS_USED) + extiGetAndClearGroup2(1U << (32 - 32), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI32_ISR) + STM32_EXTI32_ISR(pr, 32); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc new file mode 100644 index 0000000..3ad874f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti33.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti33.inc + * @brief Shared EXTI33 handler. + * + * @addtogroup STM32_EXTI33_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI33_PRIORITY) +#error "STM32_IRQ_EXTI33_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI33_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI33_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti33_irq_init(void) { +#if defined(STM32_EXTI33_IS_USED) + nvicEnableVector(STM32_EXTI33_NUMBER, STM32_IRQ_EXTI33_PRIORITY); +#endif +} + +static inline void exti33_irq_deinit(void) { +#if defined(STM32_EXTI33_IS_USED) + nvicDisableVector(STM32_EXTI33_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_EXTI33_IS_USED) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI33_HANDLER) +/** + * @brief EXTI[33] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI33_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup2(1U << (33 - 32), pr); + + /* Could be unused.*/ + (void)pr; + +#if defined(STM32_EXTI33_ISR) + STM32_EXTI33_ISR(pr, (33 - 32)); +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc new file mode 100644 index 0000000..a39e83d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4.inc @@ -0,0 +1,95 @@ +/* + 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 EXTIv1/stm32_exti4.inc + * @brief Shared EXTI4 handler. + * + * @addtogroup STM32_EXTI4_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI4_PRIORITY) +#error "STM32_IRQ_EXTI4_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI4_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI4_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti4_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI4_NUMBER, STM32_IRQ_EXTI4_PRIORITY); +#endif +} + +static inline void exti4_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI4_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI4_HANDLER) +/** + * @brief EXTI[4] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI4_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1(1U << 4, pr); + + exti_serve_irq(pr, 4); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc new file mode 100644 index 0000000..ddb6663 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti4_15.inc @@ -0,0 +1,108 @@ +/* + 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 EXTIv1/stm32_exti4_15.inc + * @brief Shared EXTI4_15 handler. + * + * @addtogroup STM32_EXTI4_15_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI4_15_PRIORITY) +#error "STM32_IRQ_EXTI4_15_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI4_15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI4_15_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti4_15_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI4_15_NUMBER, STM32_IRQ_EXTI4_15_PRIORITY); +#endif +} + +static inline void exti4_15_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI4_15_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI4_15_HANDLER) +/** + * @brief EXTI[4]..EXTI[15] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI4_15_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 4) | (1U << 5) | (1U << 6) | (1U << 7) | + (1U << 8) | (1U << 9) | (1U << 10) | (1U << 11) | + (1U << 12) | (1U << 13) | (1U << 14) | (1U << 15), pr); + + exti_serve_irq(pr, 4); + exti_serve_irq(pr, 5); + exti_serve_irq(pr, 6); + exti_serve_irq(pr, 7); + exti_serve_irq(pr, 8); + exti_serve_irq(pr, 9); + exti_serve_irq(pr, 10); + exti_serve_irq(pr, 11); + exti_serve_irq(pr, 12); + exti_serve_irq(pr, 13); + exti_serve_irq(pr, 14); + exti_serve_irq(pr, 15); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc new file mode 100644 index 0000000..9a52fa6 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/EXTIv1/stm32_exti5_9.inc @@ -0,0 +1,100 @@ +/* + 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 EXTIv1/stm32_exti5_9.inc + * @brief Shared EXTI5_9 handler. + * + * @addtogroup STM32_EXTI5_9_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_EXTI5_9_PRIORITY) +#error "STM32_IRQ_EXTI5_9_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_EXTI5_9_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_EXTI5_9_PRIORITY" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void exti5_9_irq_init(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicEnableVector(STM32_EXTI5_9_NUMBER, STM32_IRQ_EXTI5_9_PRIORITY); +#endif +} + +static inline void exti5_9_irq_deinit(void) { +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) + nvicDisableVector(STM32_EXTI5_9_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (HAL_USE_PAL && (PAL_USE_WAIT || PAL_USE_CALLBACKS)) || defined(__DOXYGEN__) +#if !defined(STM32_DISABLE_EXTI5_9_HANDLER) +/** + * @brief EXTI[5]..EXTI[9] interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_EXTI5_9_HANDLER) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + + extiGetAndClearGroup1((1U << 5) | (1U << 6) | (1U << 7) | (1U << 8) | + (1U << 9), pr); + + exti_serve_irq(pr, 5); + exti_serve_irq(pr, 6); + exti_serve_irq(pr, 7); + exti_serve_irq(pr, 8); + exti_serve_irq(pr, 9); + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk new file mode 100644 index 0000000..734c3a0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c new file mode 100644 index 0000000..38e5ff6 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c @@ -0,0 +1,566 @@ +/*
+ 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 FDCANv1/hal_can_lld.c
+ * @brief STM32 CAN subsystem low level driver source.
+ *
+ * @addtogroup CAN
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* Filter Standard Element Size in bytes.*/
+#define SRAMCAN_FLS_SIZE (1U * 4U)
+
+/* Filter Extended Element Size in bytes.*/
+#define SRAMCAN_FLE_SIZE (2U * 4U)
+
+/* RX FIFO 0 Elements Size in bytes.*/
+#define SRAMCAN_RF0_SIZE (18U * 4U)
+
+/* RX FIFO 1 Elements Size in bytes.*/
+#define SRAMCAN_RF1_SIZE (18U * 4U)
+
+/* RX Buffer Size in bytes.*/
+#define SRAMCAN_RB_SIZE (18U * 4U)
+
+/* TX Event FIFO Elements Size in bytes.*/
+#define SRAMCAN_TEF_SIZE (2U * 4U)
+
+/* TX FIFO/Queue Elements Size in bytes.*/
+#define SRAMCAN_TB_SIZE (18U * 4U)
+
+/* Trigger Memory Size in bytes.*/
+#define SRAMCAN_TM_SIZE (2U * 4U)
+
+/* Filter List Standard Start Address.*/
+#define SRAMCAN_FLSSA ((uint32_t)0)
+
+/* Filter List Extended Start Address.*/
+#define SRAMCAN_FLESA ((uint32_t)(SRAMCAN_FLSSA + \
+ (STM32_FDCAN_FLS_NBR * SRAMCAN_FLS_SIZE)))
+
+/* RX FIFO 0 Start Address.*/
+#define SRAMCAN_RF0SA ((uint32_t)(SRAMCAN_FLESA + \
+ (STM32_FDCAN_FLE_NBR * SRAMCAN_FLE_SIZE)))
+
+/* RX FIFO 1 Start Address.*/
+#define SRAMCAN_RF1SA ((uint32_t)(SRAMCAN_RF0SA + \
+ (STM32_FDCAN_RF0_NBR * SRAMCAN_RF0_SIZE)))
+
+/* RX Buffer Start Address.*/
+#define SRAMCAN_RBSA ((uint32_t)(SRAMCAN_RF1SA + \
+ (STM32_FDCAN_RF1_NBR * SRAMCAN_RF1_SIZE)))
+
+/* TX Event FIFO Start Address.*/
+#define SRAMCAN_TEFSA ((uint32_t)(SRAMCAN_RBSA + \
+ (STM32_FDCAN_RB_NBR * SRAMCAN_RB_SIZE)))
+
+/* TX Buffers Start Address.*/
+#define SRAMCAN_TBSA ((uint32_t)(SRAMCAN_TEFSA + \
+ (STM32_FDCAN_TEF_NBR * SRAMCAN_TEF_SIZE)))
+
+/* Trigger Memory Start Address.*/
+#define SRAMCAN_TMSA ((uint32_t)(SRAMCAN_TBSA + \
+ (STM32_FDCAN_TB_NBR * SRAMCAN_TB_SIZE)))
+
+/* Message RAM size.*/
+#define SRAMCAN_SIZE ((uint32_t)(SRAMCAN_TMSA + \
+ (STM32_FDCAN_TM_NBR * SRAMCAN_TM_SIZE)))
+
+
+#define TIMEOUT_INIT_MS 250U
+#define TIMEOUT_CSA_MS 250U
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief CAN1 driver identifier.*/
+#if STM32_CAN_USE_FDCAN1 || defined(__DOXYGEN__)
+CANDriver CAND1;
+#endif
+
+/** @brief CAN2 driver identifier.*/
+#if STM32_CAN_USE_FDCAN2 || defined(__DOXYGEN__)
+CANDriver CAND2;
+#endif
+
+/** @brief CAN3 driver identifier.*/
+#if STM32_CAN_USE_FDCAN3 || defined(__DOXYGEN__)
+CANDriver CAND3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const uint8_t dlc_to_bytes[] = {
+ 0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
+ 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U
+};
+
+static uint32_t canclk;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static bool fdcan_clock_stop(CANDriver *canp) {
+ systime_t start, end;
+
+ /* Requesting clock stop then waiting for it to happen.*/
+ canp->fdcan->CCCR |= FDCAN_CCCR_CSR;
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS));
+ while ((canp->fdcan->CCCR & FDCAN_CCCR_CSA) != 0U) {
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return true;
+ }
+ osalThreadSleepS(1);
+ }
+
+ return false;
+}
+
+static bool fdcan_init_mode(CANDriver *canp) {
+ systime_t start, end;
+
+ /* Going in initialization mode then waiting for it to happen.*/
+ canp->fdcan->CCCR |= FDCAN_CCCR_INIT;
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS));
+ while ((canp->fdcan->CCCR & FDCAN_CCCR_INIT) == 0U) {
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return true;
+ }
+ osalThreadSleepS(1);
+ }
+
+ return false;
+}
+
+static bool fdcan_active_mode(CANDriver *canp) {
+ systime_t start, end;
+
+ /* Going in initialization mode then waiting for it to happen.*/
+ canp->fdcan->CCCR &= ~FDCAN_CCCR_INIT;
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS));
+ while ((canp->fdcan->CCCR & FDCAN_CCCR_INIT) != 0U) {
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return true;
+ }
+ osalThreadSleepS(1);
+ }
+
+ return false;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level CAN driver initialization.
+ *
+ * @notapi
+ */
+void can_lld_init(void) {
+
+ canclk = 0U;
+
+ /* Unit reset.*/
+ rccResetFDCAN();
+
+#if STM32_CAN_USE_FDCAN1
+ /* Driver initialization.*/
+ canObjectInit(&CAND1);
+ CAND1.fdcan = FDCAN1;
+ CAND1.ram_base = (uint32_t *) (SRAMCAN_BASE + 0U * SRAMCAN_SIZE);
+#endif
+
+#if STM32_CAN_USE_FDCAN2
+ /* Driver initialization.*/
+ canObjectInit(&CAND2);
+ CAND2.fdcan = FDCAN2;
+ CAND2.ram_base = (uint32_t *) (SRAMCAN_BASE + 1U * SRAMCAN_SIZE);
+#endif
+
+#if STM32_CAN_USE_FDCAN3
+ /* Driver initialization.*/
+ canObjectInit(&CAND3);
+ CAND3.fdcan = FDCAN3;
+ CAND3.ram_base = (uint32_t *) (SRAMCAN_BASE + 2U * SRAMCAN_SIZE);
+#endif
+}
+
+/**
+ * @brief Configures and activates the CAN peripheral.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @return The operation result.
+ * @retval false if the operation succeeded.
+ * @retval true if the operation failed.
+ *
+ * @notapi
+ */
+bool can_lld_start(CANDriver *canp) {
+
+ /* Clock activation.*/
+ rccEnableFDCAN(true);
+
+ /* If it is the first activation then performing some extra
+ initializations.*/
+ if (canclk == 0U) {
+ for (uint32_t *wp = canp->ram_base;
+ wp < canp->ram_base + SRAMCAN_SIZE;
+ wp += 1U) {
+ *wp = (uint32_t)0U;
+ }
+ }
+
+#if STM32_CAN_USE_FDCAN1
+ if (&CAND1 == canp) {
+ canclk |= 1U;
+ }
+#endif
+
+#if STM32_CAN_USE_FDCAN2
+ if (&CAND2 == canp) {
+ canclk |= 2U;
+ }
+#endif
+
+#if STM32_CAN_USE_FDCAN3
+ if (&CAND3 == canp) {
+ canclk |= 4U;
+ }
+#endif
+
+ /* Requesting clock stop.*/
+ if (fdcan_clock_stop(canp)) {
+ osalDbgAssert(false, "CAN clock stop failed, check clocks and pin config");
+ return true;
+ }
+
+ /* Going in initialization mode.*/
+ if (fdcan_init_mode(canp)) {
+ osalDbgAssert(false, "CAN initialization failed, check clocks and pin config");
+ return true;
+ }
+
+ /* Configuration can be performed now.*/
+ canp->fdcan->CCCR |= FDCAN_CCCR_CCE;
+
+ /* Setting up operation mode except driver-controlled bits.*/
+ canp->fdcan->DBTP = canp->config->DBTP;
+ canp->fdcan->CCCR = canp->config->CCCR & ~(FDCAN_CCCR_CSR | FDCAN_CCCR_CSA |
+ FDCAN_CCCR_CCE | FDCAN_CCCR_INIT);
+ canp->fdcan->TEST = canp->config->TEST;
+
+ /* Enabling interrupts, only using interrupt zero.*/
+ canp->fdcan->IR = (uint32_t)-1;
+ canp->fdcan->IE = FDCAN_IE_RF1NE | FDCAN_IE_RF1LE |
+ FDCAN_IE_RF0NE | FDCAN_IE_RF0LE |
+ FDCAN_IE_TCE;
+ canp->fdcan->ILE = FDCAN_ILE_EINT0;
+
+ /* Going in active mode.*/
+ if (fdcan_active_mode(canp)) {
+ osalDbgAssert(false, "CAN initialization failed, check clocks and pin config");
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * @brief Deactivates the CAN peripheral.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_stop(CANDriver *canp) {
+
+ /* If in ready state then disables the CAN peripheral.*/
+ if (canp->state == CAN_READY) {
+ /* Disabling and clearing interrupts.*/
+ canp->fdcan->IE = 0U;
+ canp->fdcan->IR = (uint32_t)-1;
+ canp->fdcan->ILE = 0U;
+
+ /* Disables the peripheral.*/
+ (void) fdcan_clock_stop(canp);
+
+#if STM32_CAN_USE_FDCAN1
+ if (&CAND1 == canp) {
+ canclk &= ~1U;
+ }
+#endif
+
+#if STM32_CAN_USE_FDCAN2
+ if (&CAND2 == canp) {
+ canclk &= ~2U;
+ }
+#endif
+
+#if STM32_CAN_USE_FDCAN3
+ if (&CAND3 == canp) {
+ canclk &= ~4U;
+ }
+#endif
+
+ if (canclk == 0U) {
+ rccDisableFDCAN();
+ }
+ }
+}
+
+/**
+ * @brief Determines whether a frame can be transmitted.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ *
+ * @return The queue space availability.
+ * @retval false no space in the transmit queue.
+ * @retval true transmit slot available.
+ *
+ * @notapi
+ */
+bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) {
+
+ (void)mailbox;
+
+ return (bool)((canp->fdcan->TXFQS & FDCAN_TXFQS_TFQF) == 0U);
+}
+
+/**
+ * @brief Inserts a frame into the transmit queue.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] ctfp pointer to the CAN frame to be transmitted
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ *
+ * @notapi
+ */
+void can_lld_transmit(CANDriver *canp,
+ canmbx_t mailbox,
+ const CANTxFrame *ctfp) {
+ uint32_t *tx_address;
+
+ (void)mailbox;
+
+ osalDbgCheck(dlc_to_bytes[ctfp->DLC] <= CAN_MAX_DLC_BYTES);
+
+ /* Writing frame.*/
+ tx_address = canp->ram_base + (SRAMCAN_TBSA / sizeof (uint32_t));
+ *tx_address++ = ctfp->header32[0];
+ *tx_address++ = ctfp->header32[1];
+ for (unsigned i = 0U; i < dlc_to_bytes[ctfp->DLC]; i += 4U) {
+ *tx_address++ = ctfp->data32[i / 4U];
+ }
+}
+
+/**
+ * @brief Determines whether a frame has been received.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ *
+ * @return The queue space availability.
+ * @retval false no space in the transmit queue.
+ * @retval true transmit slot available.
+ *
+ * @notapi
+ */
+bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) {
+
+ switch (mailbox) {
+ case CAN_ANY_MAILBOX:
+ return can_lld_is_rx_nonempty(canp, 1U) ||
+ can_lld_is_rx_nonempty(canp, 2U);
+ case 1:
+ return (bool)((canp->fdcan->RXF0S & FDCAN_RXF0S_F0FL) != 0U);
+ case 2:
+ return (bool)((canp->fdcan->RXF1S & FDCAN_RXF1S_F1FL) != 0U);
+ default:
+ return false;
+ }
+}
+
+/**
+ * @brief Receives a frame from the input queue.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ * @param[out] crfp pointer to the buffer where the CAN frame is copied
+ *
+ * @notapi
+ */
+void can_lld_receive(CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp) {
+ uint32_t get_index;
+ uint32_t *rx_address;
+
+ if (mailbox == CAN_ANY_MAILBOX) {
+ if (can_lld_is_rx_nonempty(canp, 1U)) {
+ mailbox = 1U;
+ }
+ else if (can_lld_is_rx_nonempty(canp, 2U)) {
+ mailbox = 2U;
+ }
+ else {
+ return;
+ }
+ }
+
+ /* GET index, add it and the length to the rx_address.*/
+ get_index = (canp->fdcan->RXF0S & FDCAN_RXF0S_F0GI_Msk) >> FDCAN_RXF0S_F0GI_Pos;
+ rx_address = canp->ram_base + (SRAMCAN_RF0SA +
+ (get_index * SRAMCAN_RF0_SIZE)) / sizeof (uint32_t);
+ crfp->header32[0] = *rx_address++;
+ crfp->header32[1] = *rx_address++;
+
+ /* Copy message from FDCAN peripheral's SRAM to structure. RAM is restricted
+ to word aligned accesses, so up to 3 extra bytes may be copied.*/
+ for (unsigned i = 0U; i < dlc_to_bytes[crfp->DLC]; i += 4U) {
+ crfp->data32[i / 4U] = *rx_address++;
+ }
+
+ /* Acknowledge receipt by writing the get-index to the acknowledge
+ register RXFxA then re-enable RX FIFO message arrived interrupt once
+ the FIFO is emptied.*/
+ if (mailbox == 1U) {
+ uint32_t rxf0a = canp->fdcan->RXF0A;
+ rxf0a &= ~FDCAN_RXF0A_F0AI_Msk;
+ rxf0a |= get_index << FDCAN_RXF0A_F0AI_Pos;
+ canp->fdcan->RXF0A = rxf0a;
+
+ if (!can_lld_is_rx_nonempty(canp, mailbox)) {
+// canp->fdcan->IR = FDCAN_IR_RF0N;
+ canp->fdcan->IE |= FDCAN_IE_RF0NE;
+ }
+ }
+ else {
+ uint32_t rxf1a = canp->fdcan->RXF1A;
+ rxf1a &= ~FDCAN_RXF1A_F1AI_Msk;
+ rxf1a |= get_index << FDCAN_RXF1A_F1AI_Pos;
+ canp->fdcan->RXF1A = rxf1a;
+
+ if (!can_lld_is_rx_nonempty(canp, mailbox)) {
+// canp->fdcan->IR = FDCAN_IR_RF1N;
+ canp->fdcan->IE |= FDCAN_IE_RF1NE;
+ }
+ }
+}
+
+/**
+ * @brief Tries to abort an ongoing transmission.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number
+ *
+ * @notapi
+ */
+void can_lld_abort(CANDriver *canp, canmbx_t mailbox) {
+
+ (void)canp;
+ (void)mailbox;
+}
+
+#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
+/**
+ * @brief Enters the sleep mode.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_sleep(CANDriver *canp) {
+
+ (void)canp;
+}
+
+/**
+ * @brief Enforces leaving the sleep mode.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_wakeup(CANDriver *canp) {
+
+ (void)canp;
+}
+#endif /* CAN_USE_SLEEP_MODE */
+
+/**
+ * @brief FDCAN IRQ0 service routine.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+void can_lld_serve_interrupt(CANDriver *canp) {
+ uint32_t ir;
+
+ /* Getting and clearing active IRQs.*/
+ ir = canp->fdcan->IR;
+ canp->fdcan->IR = ir;
+
+ /* RX events.*/
+ if ((ir & FDCAN_IR_RF0N) != 0U) {
+ /* Disabling this source until the queue is emptied.*/
+ canp->fdcan->IE &= ~FDCAN_IE_RF0NE;
+ _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(1U));
+ }
+ if ((ir & FDCAN_IR_RF1N) != 0U) {
+ /* Disabling this source until the queue is emptied.*/
+ canp->fdcan->IE &= ~FDCAN_IE_RF1NE;
+ _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(2U));
+ }
+
+ /* Overflow events.*/
+ if ((ir & FDCAN_IR_RF0N) != 0U) {
+ _can_error_isr(canp, CAN_OVERFLOW_ERROR);
+ }
+
+ /* TX events.*/
+ if ((ir & FDCAN_IR_TC) != 0U) {
+ eventflags_t flags = 0U;
+
+ flags |= 1U;
+ _can_tx_empty_isr(canp, flags);
+ }
+}
+
+#endif /* HAL_USE_CAN */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h new file mode 100644 index 0000000..eb02c34 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h @@ -0,0 +1,470 @@ +/*
+ 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 FDCANv1/hal_can_lld.h
+ * @brief STM32 CAN subsystem low level driver header.
+ *
+ * @addtogroup CAN
+ * @{
+ */
+
+#ifndef HAL_CAN_LLD_H
+#define HAL_CAN_LLD_H
+
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Maximum number of bytes in data of CAN packets.
+ */
+#define CAN_MAX_DLC_BYTES 64
+
+/**
+ * @brief Number of transmit mailboxes.
+ */
+#define CAN_TX_MAILBOXES 1
+
+/**
+ * @brief Number of receive mailboxes.
+ */
+#define CAN_RX_MAILBOXES 2
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief CAN1 driver enable switch.
+ * @details If set to @p TRUE the support for FDCAN1 is included.
+ */
+#if !defined(STM32_CAN_USE_FDCAN1) || defined(__DOXYGEN__)
+#define STM32_CAN_USE_FDCAN1 FALSE
+#endif
+
+/**
+ * @brief CAN2 driver enable switch.
+ * @details If set to @p TRUE the support for FDCAN2 is included.
+ */
+#if !defined(STM32_CAN_USE_FDCAN2) || defined(__DOXYGEN__)
+#define STM32_CAN_USE_FDCAN2 FALSE
+#endif
+
+/**
+ * @brief CAN3 driver enable switch.
+ * @details If set to @p TRUE the support for FDCAN3 is included.
+ */
+#if !defined(STM32_CAN_USE_FDCAN3) || defined(__DOXYGEN__)
+#define STM32_CAN_USE_FDCAN3 FALSE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_FDCAN1)
+#error "STM32_HAS_FDCAN1 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_FDCAN2)
+#error "STM32_HAS_FDCAN2 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_FDCAN3)
+#error "STM32_HAS_FDCAN3 not defined in registry"
+#endif
+
+#if STM32_CAN_USE_FDCAN1 && !STM32_HAS_FDCAN1
+#error "FDCAN1 not present in the selected device"
+#endif
+
+#if STM32_CAN_USE_FDCAN2 && !STM32_HAS_FDCAN2
+#error "FDCAN2 not present in the selected device"
+#endif
+
+#if STM32_CAN_USE_FDCAN3 && !STM32_HAS_FDCAN3
+#error "FDCAN3 not present in the selected device"
+#endif
+
+#if !STM32_CAN_USE_FDCAN1 && !STM32_CAN_USE_FDCAN2 && !STM32_CAN_USE_FDCAN3
+#error "CAN driver activated but no FDCAN peripheral assigned"
+#endif
+
+#if !defined(STM32_FDCAN_FLS_NBR)
+#error "STM32_FDCAN_FLS_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_FLE_NBR)
+#error "STM32_FDCAN_FLE_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_RF0_NBR)
+#error "STM32_FDCAN_RF0_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_RF1_NBR)
+#error "STM32_FDCAN_RF1_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_RB_NBR)
+#error "STM32_FDCAN_RB_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_TEF_NBR)
+#error "STM32_FDCAN_TEF_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_TB_NBR)
+#error "STM32_FDCAN_TB_NBR not defined in registry"
+#endif
+
+#if !defined(STM32_FDCAN_TM_NBR)
+#error "STM32_FDCAN_TM_NBR not defined in registry"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an CAN driver.
+ */
+typedef struct CANDriver CANDriver;
+
+/**
+ * @brief Type of a transmission mailbox index.
+ */
+typedef uint32_t canmbx_t;
+
+#if (CAN_ENFORCE_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a CAN notification callback.
+ *
+ * @param[in] canp pointer to the @p CANDriver object triggering the
+ * callback
+ * @param[in] flags flags associated to the mailbox callback
+ */
+typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags);
+#endif
+
+/**
+ * @brief CAN transmission frame.
+ * @note Accessing the frame data as word16 or word32 is not portable
+ * because machine data endianness, it can be still useful for a
+ * quick filling.
+ */
+typedef struct {
+ /**
+ * @brief Frame header.
+ */
+ union {
+ struct {
+ union {
+ uint32_t EID:29; /**< @brief Extended identifier. */
+ struct {
+ uint32_t _R1:18; /**< @brief Reserved for offset. */
+ uint32_t SID:11; /**< @brief Standard identifier. */
+ uint32_t RTR:1; /**< @brief Remote transmit request.*/
+ uint32_t XTD:1; /**< @brief Extended identifier. */
+ uint32_t ESI:1; /**< @brief Error state indicator. */
+ };
+ };
+ uint32_t _R2:16;
+ uint32_t DLC:4; /**< @brief Data length code. */
+ uint32_t BPS:1; /**< @brief Accepted non-matching
+ frame. */
+ uint32_t FDF:1; /**< @brief FDCAN frame format. */
+ uint32_t _R3:1;
+ uint32_t EFC:1; /**< @brief Event FIFO control. */
+ uint32_t MM:8; /**< @brief Message event marker. */
+ };
+ uint32_t header32[2];
+ };
+ /**
+ * @brief Frame data.
+ */
+ union {
+ uint8_t data8[CAN_MAX_DLC_BYTES];
+ uint16_t data16[CAN_MAX_DLC_BYTES / 2];
+ uint32_t data32[CAN_MAX_DLC_BYTES / 4];
+ };
+} CANTxFrame;
+
+/**
+ * @brief CAN received frame.
+ * @note Accessing the frame data as word16 or word32 is not portable
+ * because machine data endianness, it can be still useful for a
+ * quick filling.
+ */
+typedef struct {
+ /**
+ * @brief Frame header.
+ */
+ struct {
+ union {
+ uint32_t EID:29; /**< @brief Extended Identifier. */
+ struct {
+ uint32_t _R1:18;
+ uint32_t SID:11; /**< @brief Standard identifier. */
+ uint32_t RTR:1; /**< @brief Remote transmit request.*/
+ uint32_t XTD:1; /**< @brief Extended identifier. */
+ uint32_t ESI:1; /**< @brief Error state indicator. */
+ };
+ };
+ uint16_t RXTS:16; /**< @brief TX time stamp. */
+ uint8_t DLC:4; /**< @brief Data length code. */
+ uint8_t BRS:1; /**< @brief Bit rate switch. */
+ uint8_t FDF:1; /**< @brief FDCAN frame format. */
+ uint8_t _R2:2;
+ uint8_t FIDX:7; /**< @brief Filter index. */
+ uint8_t ANMF:1; /**< @brief Accepted non-matching
+ frame. */
+ };
+ uint32_t header32[2];
+ /**
+ * @brief Frame data.
+ */
+ union {
+ uint8_t data8[CAN_MAX_DLC_BYTES];
+ uint16_t data16[CAN_MAX_DLC_BYTES / 2];
+ uint32_t data32[CAN_MAX_DLC_BYTES / 4];
+ };
+} CANRxFrame;
+
+/**
+ * @brief CAN standard filter.
+ * @note Accessing the frame data as word16 or word32 is not portable
+ * because machine data endianness, it can be still useful for a
+ * quick filling.
+ */
+typedef struct {
+ union {
+ struct {
+ uint16_t SFID2:11;
+ uint8_t _R1:5;
+ uint16_t SFID1:11;
+ uint8_t SFEC:3;
+ uint8_t SFT:2;
+ };
+ union {
+ uint32_t data32;
+ uint16_t data16[2];
+ uint8_t data8[4];
+ };
+ };
+} CANRxStandardFilter;
+
+
+/**
+ * @brief CAN extended filter.
+ * @note Accessing the frame data as word16 or word32 is not portable
+ * because machine data endianness, it can be still useful for a
+ * quick filling.
+*/
+typedef struct {
+ union {
+ struct {
+ uint32_t EFID1:29;
+ uint8_t EFEC:3;
+ uint32_t EFID2:29;
+ uint8_t _R1:1;
+ uint8_t EFT:2;
+ };
+ union {
+ uint32_t data32[2];
+ uint16_t data16[4];
+ uint8_t data8[8];
+ };
+ };
+} CANRxExtendedFilter;
+
+
+/**
+ * @brief Driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Data bit timing and prescaler register.
+ */
+ uint32_t DBTP;
+ /**
+ * @brief CC control register.
+ */
+ uint32_t CCCR;
+ /**
+ * @brief Test configuration register.
+ */
+ uint32_t TEST;
+} CANConfig;
+
+/**
+ * @brief Structure representing an CAN driver.
+ */
+struct CANDriver {
+ /**
+ * @brief Driver state.
+ */
+ canstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const CANConfig *config;
+ /**
+ * @brief Transmission threads queue.
+ */
+ threads_queue_t txqueue;
+ /**
+ * @brief Receive threads queue.
+ */
+ threads_queue_t rxqueue;
+#if (CAN_ENFORCE_USE_CALLBACKS == FALSE) || defined(__DOXYGEN__)
+ /**
+ * @brief One or more frames become available.
+ * @note After broadcasting this event it will not be broadcasted again
+ * until the received frames queue has been completely emptied. It
+ * is <b>not</b> broadcasted for each received frame. It is
+ * responsibility of the application to empty the queue by
+ * repeatedly invoking @p canReceive() when listening to this event.
+ * This behavior minimizes the interrupt served by the system
+ * because CAN traffic.
+ * @note The flags associated to the listeners will indicate which
+ * receive mailboxes become non-empty.
+ */
+ event_source_t rxfull_event;
+ /**
+ * @brief One or more transmission mailbox become available.
+ * @note The flags associated to the listeners will indicate which
+ * transmit mailboxes become empty.
+ * @note The upper 16 bits are transmission error flags associated
+ * to the transmit mailboxes.
+ */
+ event_source_t txempty_event;
+ /**
+ * @brief A CAN bus error happened.
+ * @note The flags associated to the listeners will indicate that
+ * receive error(s) have occurred.
+ * @note In this implementation the upper 16 bits are filled with the
+ * unprocessed content of the ESR register.
+ */
+ event_source_t error_event;
+#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__)
+ /**
+ * @brief Entering sleep state event.
+ */
+ event_source_t sleep_event;
+ /**
+ * @brief Exiting sleep state event.
+ */
+ event_source_t wakeup_event;
+#endif /* CAN_USE_SLEEP_MODE */
+#else /* CAN_ENFORCE_USE_CALLBACKS == TRUE */
+ /**
+ * @brief One or more frames become available.
+ * @note After calling this function it will not be called again
+ * until the received frames queue has been completely emptied. It
+ * is <b>not</b> called for each received frame. It is
+ * responsibility of the application to empty the queue by
+ * repeatedly invoking @p chTryReceiveI().
+ * This behavior minimizes the interrupt served by the system
+ * because CAN traffic.
+ */
+ can_callback_t rxfull_cb;
+ /**
+ * @brief One or more transmission mailbox become available.
+ * @note The flags associated to the callback will indicate which
+ * transmit mailboxes become empty.
+ */
+ can_callback_t txempty_cb;
+ /**
+ * @brief A CAN bus error happened.
+ */
+ can_callback_t error_cb;
+#if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__)
+ /**
+ * @brief Exiting sleep state.
+ */
+ can_callback_t wakeup_cb;
+#endif
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the CAN registers.
+ */
+ FDCAN_GlobalTypeDef *fdcan;
+ /**
+ * @brief Pointer to FDCAN RAM base.
+ */
+ uint32_t *ram_base;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_CAN_USE_FDCAN1 && !defined(__DOXYGEN__)
+extern CANDriver CAND1;
+#endif
+
+#if STM32_CAN_USE_FDCAN2 && !defined(__DOXYGEN__)
+extern CANDriver CAND2;
+#endif
+
+#if STM32_CAN_USE_FDCAN3 && !defined(__DOXYGEN__)
+extern CANDriver CAND3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void can_lld_init(void);
+ bool can_lld_start(CANDriver *canp);
+ void can_lld_stop(CANDriver *canp);
+ bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox);
+ void can_lld_transmit(CANDriver *canp,
+ canmbx_t mailbox,
+ const CANTxFrame *crfp);
+ bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox);
+ void can_lld_receive(CANDriver *canp,
+ canmbx_t mailbox,
+ CANRxFrame *ctfp);
+ void can_lld_abort(CANDriver *canp,
+ canmbx_t mailbox);
+#if CAN_USE_SLEEP_MODE
+ void can_lld_sleep(CANDriver *canp);
+ void can_lld_wakeup(CANDriver *canp);
+#endif /* CAN_USE_SLEEP_MODE */
+ void can_lld_serve_interrupt(CANDriver *canp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_CAN */
+
+#endif /* HAL_CAN_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc new file mode 100644 index 0000000..4f6fd37 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan1.inc @@ -0,0 +1,106 @@ +/* + 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 FDCANv1/stm32_fdcan1.inc + * @brief Shared FDCAN1 handler. + * + * @addtogroup STM32_FDCAN1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_FDCAN1) +#error "STM32_HAS_FDCAN1 not defined in registry" +#endif + +#if STM32_HAS_FDCAN1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_FDCAN1_PRIORITY) +#error "STM32_IRQ_FDCAN1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_FDCAN1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_FDCAN1_PRIORITY" +#endif + +#endif /* STM32_HAS_FDCAN1 */ + +/* Other checks.*/ +#if HAL_USE_CAN && STM32_CAN_USE_FDCAN1 +#define STM32_FDCAN1_IS_USED TRUE +#else +#define STM32_FDCAN1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void fdcan1_irq_init(void) { +#if STM32_FDCAN1_IS_USED + nvicEnableVector(STM32_FDCAN1_IT0_NUMBER, STM32_IRQ_FDCAN1_PRIORITY); +#endif +} + +static inline void fdcan1_irq_deinit(void) { +#if STM32_FDCAN1_IS_USED + nvicDisableVector(STM32_FDCAN1_IT0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_FDCAN1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief FDCAN1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_FDCAN1_IT0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_serve_interrupt(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc new file mode 100644 index 0000000..2226260 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan2.inc @@ -0,0 +1,106 @@ +/* + 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 FDCANv1/stm32_fdcan2.inc + * @brief Shared FDCAN2 handler. + * + * @addtogroup STM32_FDCAN2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_FDCAN2) +#error "STM32_HAS_FDCAN2 not defined in registry" +#endif + +#if STM32_HAS_FDCAN2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_FDCAN2_PRIORITY) +#error "STM32_IRQ_FDCAN2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_FDCAN2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_FDCAN2_PRIORITY" +#endif + +#endif /* STM32_HAS_FDCAN2 */ + +/* Other checks.*/ +#if HAL_USE_CAN && STM32_CAN_USE_FDCAN2 +#define STM32_FDCAN2_IS_USED TRUE +#else +#define STM32_FDCAN2_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void fdcan2_irq_init(void) { +#if STM32_FDCAN2_IS_USED + nvicEnableVector(STM32_FDCAN2_IT0_NUMBER, STM32_IRQ_FDCAN2_PRIORITY); +#endif +} + +static inline void fdcan2_irq_deinit(void) { +#if STM32_FDCAN2_IS_USED + nvicDisableVector(STM32_FDCAN2_IT0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_FDCAN2_IS_USED|| defined(__DOXYGEN__) +/** + * @brief FDCAN2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_FDCAN2_IT0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_serve_interrupt(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc new file mode 100644 index 0000000..153a29f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/FDCANv1/stm32_fdcan3.inc @@ -0,0 +1,106 @@ +/* + 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 FDCANv1/stm32_fdcan3.inc + * @brief Shared FDCAN3 handler. + * + * @addtogroup STM32_FDCAN3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_FDCAN3) +#error "STM32_HAS_FDCAN3 not defined in registry" +#endif + +#if STM32_HAS_FDCAN3 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_FDCAN3_PRIORITY) +#error "STM32_IRQ_FDCAN3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_FDCAN3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_FDCAN3_PRIORITY" +#endif + +#endif /* STM32_HAS_FDCAN3 */ + +/* Other checks.*/ +#if HAL_USE_CAN && STM32_CAN_USE_FDCAN3 +#define STM32_FDCAN3_IS_USED TRUE +#else +#define STM32_FDCAN3_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void fdcan3_irq_init(void) { +#if STM32_FDCAN3_IS_USED + nvicEnableVector(STM32_FDCAN3_IT0_NUMBER, STM32_IRQ_FDCAN3_PRIORITY); +#endif +} + +static inline void fdcan3_irq_deinit(void) { +#if STM32_FDCAN3_IS_USED + nvicDisableVector(STM32_FDCAN3_IT0_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_FDCAN3_IS_USED|| defined(__DOXYGEN__) +/** + * @brief FDCAN3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_FDCAN3_IT0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_serve_interrupt(&CAND3); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk new file mode 100644 index 0000000..5e428a7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c new file mode 100644 index 0000000..99106bc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.c @@ -0,0 +1,300 @@ +/*
+ 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 GPIOv1/hal_pal_lld.c
+ * @brief STM32 PAL low level driver code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#if STM32_HAS_GPIOG
+#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
+ RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
+ RCC_APB2ENR_IOPEEN | RCC_APB2ENR_IOPFEN | \
+ RCC_APB2ENR_IOPGEN | RCC_APB2ENR_AFIOEN)
+#elif STM32_HAS_GPIOE
+#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
+ RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
+ RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN)
+#else
+#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
+ RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
+ RCC_APB2ENR_AFIOEN)
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Event records for the 16 GPIO EXTI channels.
+ */
+palevent_t _pal_events[16];
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 I/O ports configuration.
+ * @details Ports A-D(E, F, G) clocks enabled, AFIO clock enabled.
+ *
+ * @param[in] config the STM32 ports configuration
+ *
+ * @notapi
+ */
+void _pal_lld_init(const PALConfig *config) {
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+ unsigned i;
+
+ for (i = 0; i < 16; i++) {
+ _pal_init_event(i);
+ }
+#endif
+
+ /*
+ * Enables the GPIO related clocks.
+ */
+ rccEnableAPB2(APB2_EN_MASK, true);
+
+ /*
+ * Initial GPIO setup.
+ */
+ GPIOA->ODR = config->PAData.odr;
+ GPIOA->CRH = config->PAData.crh;
+ GPIOA->CRL = config->PAData.crl;
+ GPIOB->ODR = config->PBData.odr;
+ GPIOB->CRH = config->PBData.crh;
+ GPIOB->CRL = config->PBData.crl;
+ GPIOC->ODR = config->PCData.odr;
+ GPIOC->CRH = config->PCData.crh;
+ GPIOC->CRL = config->PCData.crl;
+ GPIOD->ODR = config->PDData.odr;
+ GPIOD->CRH = config->PDData.crh;
+ GPIOD->CRL = config->PDData.crl;
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+ GPIOE->ODR = config->PEData.odr;
+ GPIOE->CRH = config->PEData.crh;
+ GPIOE->CRL = config->PEData.crl;
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+ GPIOF->ODR = config->PFData.odr;
+ GPIOF->CRH = config->PFData.crh;
+ GPIOF->CRL = config->PFData.crl;
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+ GPIOG->ODR = config->PGData.odr;
+ GPIOG->CRH = config->PGData.crh;
+ GPIOG->CRL = config->PGData.crl;
+#endif
+#endif
+#endif
+}
+
+/**
+ * @brief Pads mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note @p PAL_MODE_UNCONNECTED is implemented as push pull output at 2MHz.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port the port identifier
+ * @param[in] mask the group mask
+ * @param[in] mode the mode
+ *
+ * @notapi
+ */
+void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode) {
+ static const uint8_t cfgtab[] = {
+ 4, /* PAL_MODE_RESET, implemented as input.*/
+ 2, /* PAL_MODE_UNCONNECTED, implemented as push pull output 2MHz.*/
+ 4, /* PAL_MODE_INPUT */
+ 8, /* PAL_MODE_INPUT_PULLUP */
+ 8, /* PAL_MODE_INPUT_PULLDOWN */
+ 0, /* PAL_MODE_INPUT_ANALOG */
+ 3, /* PAL_MODE_OUTPUT_PUSHPULL, 50MHz.*/
+ 7, /* PAL_MODE_OUTPUT_OPENDRAIN, 50MHz.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 8, /* Reserved.*/
+ 0xB, /* PAL_MODE_STM32_ALTERNATE_PUSHPULL, 50MHz.*/
+ 0xF, /* PAL_MODE_STM32_ALTERNATE_OPENDRAIN, 50MHz.*/
+ };
+ uint32_t mh, ml, crh, crl, cfg;
+ unsigned i;
+
+ if (mode == PAL_MODE_INPUT_PULLUP)
+ port->BSRR = mask;
+ else if (mode == PAL_MODE_INPUT_PULLDOWN)
+ port->BRR = mask;
+ cfg = cfgtab[mode];
+ mh = ml = crh = crl = 0;
+ for (i = 0; i < 8; i++) {
+ ml <<= 4;
+ mh <<= 4;
+ crl <<= 4;
+ crh <<= 4;
+ if ((mask & 0x0080) == 0)
+ ml |= 0xf;
+ else
+ crl |= cfg;
+ if ((mask & 0x8000) == 0)
+ mh |= 0xf;
+ else
+ crh |= cfg;
+ mask <<= 1;
+ }
+ port->CRH = (port->CRH & mh) | crh;
+ port->CRL = (port->CRL & ml) | crl;
+}
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Pad event enable.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad event mode
+ *
+ * @notapi
+ */
+void _pal_lld_enablepadevent(ioportid_t port,
+ iopadid_t pad,
+ ioeventmode_t mode) {
+
+ uint32_t padmask, cridx, croff, crmask, portidx;
+
+ /* Mask of the pad.*/
+ padmask = 1U << (uint32_t)pad;
+
+ /* Multiple channel setting of the same channel not allowed, first disable
+ it. This is done because on STM32 the same channel cannot be mapped on
+ multiple ports.*/
+ osalDbgAssert(((EXTI->RTSR & padmask) == 0U) &&
+ ((EXTI->FTSR & padmask) == 0U), "channel already in use");
+
+ /* Index and mask of the SYSCFG CR register to be used.*/
+ cridx = (uint32_t)pad >> 2U;
+ croff = ((uint32_t)pad & 3U) * 4U;
+ crmask = ~(0xFU << croff);
+
+ /* Port index is obtained assuming that GPIO ports are placed at regular
+ 0x400 intervals in memory space. So far this is true for all devices.*/
+ portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU;
+
+ /* Port selection in SYSCFG.*/
+ AFIO->EXTICR[cridx] = (AFIO->EXTICR[cridx] & crmask) | (portidx << croff);
+
+ /* Programming edge registers.*/
+ if (mode & PAL_EVENT_MODE_RISING_EDGE)
+ EXTI->RTSR |= padmask;
+ else
+ EXTI->RTSR &= ~padmask;
+ if (mode & PAL_EVENT_MODE_FALLING_EDGE)
+ EXTI->FTSR |= padmask;
+ else
+ EXTI->FTSR &= ~padmask;
+
+ /* Programming interrupt and event registers.*/
+ EXTI->IMR |= padmask;
+ EXTI->EMR &= ~padmask;
+}
+
+/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) {
+ uint32_t padmask, rtsr1, ftsr1;
+
+ rtsr1 = EXTI->RTSR;
+ ftsr1 = EXTI->FTSR;
+
+ /* Mask of the pad.*/
+ padmask = 1U << (uint32_t)pad;
+
+ /* If either RTRS1 or FTSR1 is enabled then the channel is in use.*/
+ if (((rtsr1 | ftsr1) & padmask) != 0U) {
+ uint32_t cridx, croff, crport, portidx;
+
+ /* Index and mask of the SYSCFG CR register to be used.*/
+ cridx = (uint32_t)pad >> 2U;
+ croff = ((uint32_t)pad & 3U) * 4U;
+
+ /* Port index is obtained assuming that GPIO ports are placed at regular
+ 0x400 intervals in memory space. So far this is true for all devices.*/
+ portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU;
+
+ crport = (AFIO->EXTICR[cridx] >> croff) & 0xFU;
+
+ osalDbgAssert(crport == portidx, "channel mapped on different port");
+
+ /* Disabling channel.*/
+ EXTI->IMR &= ~padmask;
+ EXTI->EMR &= ~padmask;
+ EXTI->RTSR = rtsr1 & ~padmask;
+ EXTI->FTSR = ftsr1 & ~padmask;
+ EXTI->PR = padmask;
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT
+ /* Callback cleared and/or thread reset.*/
+ _pal_clear_event(pad);
+#endif
+ }
+}
+#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h new file mode 100644 index 0000000..63bc006 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv1/hal_pal_lld.h @@ -0,0 +1,459 @@ +/*
+ 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 GPIOv1/hal_pal_lld.h
+ * @brief STM32 PAL low level driver header.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#ifndef HAL_PAL_LLD_H
+#define HAL_PAL_LLD_H
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Unsupported modes and specific modes */
+/*===========================================================================*/
+
+/**
+ * @name STM32-specific I/O mode flags
+ * @{
+ */
+/**
+ * @brief STM32 specific alternate push-pull output mode.
+ */
+#define PAL_MODE_STM32_ALTERNATE_PUSHPULL 16
+
+/**
+ * @brief STM32 specific alternate open-drain output mode.
+ */
+#define PAL_MODE_STM32_ALTERNATE_OPENDRAIN 17
+/** @} */
+
+/*===========================================================================*/
+/* I/O Ports Types and constants. */
+/*===========================================================================*/
+
+/**
+ * @name Port related definitions
+ * @{
+ */
+/**
+ * @brief Width, in bits, of an I/O port.
+ */
+#define PAL_IOPORTS_WIDTH 16
+
+/**
+ * @brief Whole port mask.
+ * @details This macro specifies all the valid bits into a port.
+ */
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
+/** @} */
+
+/**
+ * @name Line handling macros
+ * @{
+ */
+/**
+ * @brief Forms a line identifier.
+ * @details A port/pad pair are encoded into an @p ioline_t type. The encoding
+ * of this type is platform-dependent.
+ * @note In this driver the pad number is encoded in the lower 4 bits of
+ * the GPIO address which are guaranteed to be zero.
+ */
+#define PAL_LINE(port, pad) \
+ ((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad)))
+
+/**
+ * @brief Decodes a port identifier from a line identifier.
+ */
+#define PAL_PORT(line) \
+ ((GPIO_TypeDef *)(((uint32_t)(line)) & 0xFFFFFFF0U))
+
+/**
+ * @brief Decodes a pad identifier from a line identifier.
+ */
+#define PAL_PAD(line) \
+ ((uint32_t)((uint32_t)(line) & 0x0000000FU))
+
+/**
+ * @brief Value identifying an invalid line.
+ */
+#define PAL_NOLINE 0U
+/** @} */
+
+/**
+ * @brief GPIO port setup info.
+ */
+typedef struct {
+ /** Initial value for ODR register.*/
+ uint32_t odr;
+ /** Initial value for CRL register.*/
+ uint32_t crl;
+ /** Initial value for CRH register.*/
+ uint32_t crh;
+} stm32_gpio_setup_t;
+
+/**
+ * @brief STM32 GPIO static initializer.
+ * @details An instance of this structure must be passed to @p palInit() at
+ * system startup time in order to initialize the digital I/O
+ * subsystem. This represents only the initial setup, specific pads
+ * or whole ports can be reprogrammed at later time.
+ */
+typedef struct {
+ /** @brief Port A setup data.*/
+ stm32_gpio_setup_t PAData;
+ /** @brief Port B setup data.*/
+ stm32_gpio_setup_t PBData;
+ /** @brief Port C setup data.*/
+ stm32_gpio_setup_t PCData;
+ /** @brief Port D setup data.*/
+ stm32_gpio_setup_t PDData;
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+ /** @brief Port E setup data.*/
+ stm32_gpio_setup_t PEData;
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+ /** @brief Port F setup data.*/
+ stm32_gpio_setup_t PFData;
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+ /** @brief Port G setup data.*/
+ stm32_gpio_setup_t PGData;
+#endif
+#endif
+#endif
+} PALConfig;
+
+/**
+ * @brief Digital I/O port sized unsigned type.
+ */
+typedef uint32_t ioportmask_t;
+
+/**
+ * @brief Digital I/O modes.
+ */
+typedef uint32_t iomode_t;
+
+/**
+ * @brief Type of an I/O line.
+ */
+typedef uint32_t ioline_t;
+
+/**
+ * @brief Type of an event mode.
+ */
+typedef uint32_t ioeventmode_t;
+
+/**
+ * @brief Port Identifier.
+ * @details This type can be a scalar or some kind of pointer, do not make
+ * any assumption about it, use the provided macros when populating
+ * variables of this type.
+ */
+typedef GPIO_TypeDef * ioportid_t;
+
+/**
+ * @brief Type of an pad identifier.
+ */
+typedef uint32_t iopadid_t;
+
+/*===========================================================================*/
+/* I/O Ports Identifiers. */
+/* The low level driver wraps the definitions already present in the STM32 */
+/* firmware library. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO port A identifier.
+ */
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+#define IOPORT1 GPIOA
+#endif
+
+/**
+ * @brief GPIO port B identifier.
+ */
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+#define IOPORT2 GPIOB
+#endif
+
+/**
+ * @brief GPIO port C identifier.
+ */
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+#define IOPORT3 GPIOC
+#endif
+
+/**
+ * @brief GPIO port D identifier.
+ */
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+#define IOPORT4 GPIOD
+#endif
+
+/**
+ * @brief GPIO port E identifier.
+ */
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+#define IOPORT5 GPIOE
+#endif
+
+/**
+ * @brief GPIO port F identifier.
+ */
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+#define IOPORT6 GPIOF
+#endif
+
+/**
+ * @brief GPIO port G identifier.
+ */
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+#define IOPORT7 GPIOG
+#endif
+
+/*===========================================================================*/
+/* Implementation, some of the following macros could be implemented as */
+/* functions, if so please put them in pal_lld.c. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO ports subsystem initialization.
+ *
+ * @notapi
+ */
+#define pal_lld_init(config) _pal_lld_init(config)
+
+/**
+ * @brief Reads an I/O port.
+ * @details This function is implemented by reading the GPIO IDR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The port bits.
+ *
+ * @notapi
+ */
+#define pal_lld_readport(port) ((ioportmask_t)((port)->IDR))
+
+/**
+ * @brief Reads the output latch.
+ * @details This function is implemented by reading the GPIO ODR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The latched logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readlatch(port) ((ioportmask_t)((port)->ODR))
+
+/**
+ * @brief Writes on a I/O port.
+ * @details This function is implemented by writing the GPIO ODR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be written on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_writeport(port, bits) ((port)->ODR = (uint32_t)(bits))
+
+/**
+ * @brief Sets a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be ORed on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_setport(port, bits) ((port)->BSRR = (uint32_t)(bits))
+
+/**
+ * @brief Clears a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BRR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be cleared on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_clearport(port, bits) ((port)->BRR = (uint32_t)(bits))
+
+/**
+ * @brief Writes a group of bits.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset the group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group
+ * width are masked.
+ *
+ * @notapi
+ */
+#define pal_lld_writegroup(port, mask, offset, bits) { \
+ uint32_t w = ((~(uint32_t)(bits) & (uint32_t)(mask)) << (16U + (offset))) | \
+ ((uint32_t)(bits) & (uint32_t)(mask)) << (offset); \
+ (port)->BSRR = w; \
+}
+
+/**
+ * @brief Pads group mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] mode group mode
+ *
+ * @notapi
+ */
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
+ _pal_lld_setgroupmode(port, mask << offset, mode)
+
+/**
+ * @brief Writes a logical state on an output pad.
+ * @note Writing on pads programmed as pull-up or pull-down has the side
+ * effect to modify the resistor setting because the output latched
+ * data is used for the resistor selection.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] bit logical value, the value must be @p PAL_LOW or
+ * @p PAL_HIGH
+ *
+ * @notapi
+ */
+#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
+
+/**
+ * @brief Pad event enable.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad event mode
+ *
+ * @notapi
+ */
+#define pal_lld_enablepadevent(port, pad, mode) \
+ _pal_lld_enablepadevent(port, pad, mode)
+
+/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_disablepadevent(port, pad) \
+ _pal_lld_disablepadevent(port, pad)
+
+/**
+ * @brief Returns a PAL event structure associated to a pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_get_pad_event(port, pad) \
+ &_pal_events[pad]; (void)(port)
+
+/**
+ * @brief Returns a PAL event structure associated to a line.
+ *
+ * @param[in] line line identifier
+ *
+ * @notapi
+ */
+#define pal_lld_get_line_event(line) \
+ &_pal_events[PAL_PAD(line)]
+
+/**
+ * @brief Pad event enable check.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return Pad event status.
+ * @retval false if the pad event is disabled.
+ * @retval true if the pad event is enabled.
+ *
+ * @notapi
+ */
+#define pal_lld_ispadeventenabled(port, pad) \
+ (bool)((EXTI->IMR & (1U << (uint32_t)pad)) != 0U)
+
+#if !defined(__DOXYGEN__)
+extern const PALConfig pal_default_config;
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE)
+extern palevent_t _pal_events[16];
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _pal_lld_init(const PALConfig *config);
+ void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode);
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT
+ void _pal_lld_enablepadevent(ioportid_t port,
+ iopadid_t pad,
+ ioeventmode_t mode);
+ void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PAL */
+
+#endif /* HAL_PAL_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk new file mode 100644 index 0000000..387ed83 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c new file mode 100644 index 0000000..ef2fb9a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.c @@ -0,0 +1,271 @@ +/*
+ 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 GPIOv2/hal_pal_lld.c
+ * @brief STM32 PAL low level driver code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Event records for the 16 GPIO EXTI channels.
+ */
+palevent_t _pal_events[16];
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief PAL driver initialization.
+ *
+ * @notapi
+ */
+void _pal_lld_init(void) {
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+ unsigned i;
+
+ for (i = 0; i < 16; i++) {
+ _pal_init_event(i);
+ }
+#endif
+}
+
+/**
+ * @brief Pads mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note @p PAL_MODE_UNCONNECTED is implemented as push pull at minimum
+ * speed.
+ *
+ * @param[in] port the port identifier
+ * @param[in] mask the group mask
+ * @param[in] mode the mode
+ *
+ * @notapi
+ */
+void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode) {
+
+ uint32_t moder = (mode & PAL_STM32_MODE_MASK) >> 0;
+ uint32_t otyper = (mode & PAL_STM32_OTYPE_MASK) >> 2;
+ uint32_t ospeedr = (mode & PAL_STM32_OSPEED_MASK) >> 3;
+ uint32_t pupdr = (mode & PAL_STM32_PUPDR_MASK) >> 5;
+ uint32_t altr = (mode & PAL_STM32_ALTERNATE_MASK) >> 7;
+ uint32_t bit = 0;
+ while (true) {
+ if ((mask & 1) != 0) {
+ uint32_t altrmask, m1, m2, m4;
+
+ altrmask = altr << ((bit & 7) * 4);
+ m1 = 1 << bit;
+ m2 = 3 << (bit * 2);
+ m4 = 15 << ((bit & 7) * 4);
+ port->OTYPER = (port->OTYPER & ~m1) | otyper;
+ port->OSPEEDR = (port->OSPEEDR & ~m2) | ospeedr;
+ port->PUPDR = (port->PUPDR & ~m2) | pupdr;
+ if ((mode & PAL_STM32_MODE_MASK) == PAL_STM32_MODE_ALTERNATE) {
+ /* If going in alternate mode then the alternate number is set
+ before switching mode in order to avoid glitches.*/
+ if (bit < 8)
+ port->AFRL = (port->AFRL & ~m4) | altrmask;
+ else
+ port->AFRH = (port->AFRH & ~m4) | altrmask;
+ port->MODER = (port->MODER & ~m2) | moder;
+ }
+ else {
+ /* If going into a non-alternate mode then the mode is switched
+ before setting the alternate mode in order to avoid glitches.*/
+ port->MODER = (port->MODER & ~m2) | moder;
+ if (bit < 8)
+ port->AFRL = (port->AFRL & ~m4) | altrmask;
+ else
+ port->AFRH = (port->AFRH & ~m4) | altrmask;
+ }
+ }
+ mask >>= 1;
+ if (!mask)
+ return;
+ otyper <<= 1;
+ ospeedr <<= 2;
+ pupdr <<= 2;
+ moder <<= 2;
+ bit++;
+ }
+}
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Pad event enable.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad event mode
+ *
+ * @notapi
+ */
+void _pal_lld_enablepadevent(ioportid_t port,
+ iopadid_t pad,
+ ioeventmode_t mode) {
+
+ uint32_t padmask, cridx, croff, crmask, portidx;
+
+ /* Mask of the pad.*/
+ padmask = 1U << (uint32_t)pad;
+
+ /* Multiple channel setting of the same channel not allowed, first disable
+ it. This is done because on STM32 the same channel cannot be mapped on
+ multiple ports.*/
+ osalDbgAssert(((EXTI->RTSR1 & padmask) == 0U) &&
+ ((EXTI->FTSR1 & padmask) == 0U), "channel already in use");
+
+ /* Port index is obtained assuming that GPIO ports are placed at regular
+ 0x400 intervals in memory space. So far this is true for all devices.*/
+ portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU;
+
+ /* Index and mask of the CR register to be used.*/
+ cridx = (uint32_t)pad >> 2U;
+#if STM32_EXTI_HAS_CR == FALSE
+ croff = ((uint32_t)pad & 3U) * 4U;
+ crmask = ~(0xFU << croff);
+ SYSCFG->EXTICR[cridx] = (SYSCFG->EXTICR[cridx] & crmask) | (portidx << croff);
+#else
+ croff = ((uint32_t)pad & 3U) * 8U;
+ crmask = ~(0xFFU << croff);
+ EXTI->EXTICR[cridx] = (EXTI->EXTICR[cridx] & crmask) | (portidx << croff);
+#endif
+
+ /* Programming edge registers.*/
+ if (mode & PAL_EVENT_MODE_RISING_EDGE)
+ EXTI->RTSR1 |= padmask;
+ else
+ EXTI->RTSR1 &= ~padmask;
+ if (mode & PAL_EVENT_MODE_FALLING_EDGE)
+ EXTI->FTSR1 |= padmask;
+ else
+ EXTI->FTSR1 &= ~padmask;
+
+ /* Programming interrupt and event registers.*/
+#if defined(STM32_EXTI_ENHANCED)
+ EXTI_D1->IMR1 |= padmask;
+ EXTI_D1->EMR1 &= ~padmask;
+#else
+ EXTI->IMR1 |= padmask;
+ EXTI->EMR1 &= ~padmask;
+#endif
+}
+
+/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) {
+ uint32_t padmask, rtsr1, ftsr1;
+
+ rtsr1 = EXTI->RTSR1;
+ ftsr1 = EXTI->FTSR1;
+
+ /* Mask of the pad.*/
+ padmask = 1U << (uint32_t)pad;
+
+ /* If either RTRS1 or FTSR1 is enabled then the channel is in use.*/
+ if (((rtsr1 | ftsr1) & padmask) != 0U) {
+ uint32_t cridx, croff, crport, portidx;
+
+ /* Port index is obtained assuming that GPIO ports are placed at regular
+ 0x400 intervals in memory space. So far this is true for all devices.*/
+ portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU;
+
+ /* Index and mask of the CR register to be used.*/
+ cridx = (uint32_t)pad >> 2U;
+#if STM32_EXTI_HAS_CR == FALSE
+ croff = ((uint32_t)pad & 3U) * 4U;
+ crport = (SYSCFG->EXTICR[cridx] >> croff) & 0xFU;
+#else
+ croff = ((uint32_t)pad & 3U) * 8U;
+ crport = (EXTI->EXTICR[cridx] >> croff) & 0xFFU;
+#endif
+
+ osalDbgAssert(crport == portidx, "channel mapped on different port");
+
+#if defined(STM32_EXTI_ENHANCED)
+ /* Disabling channel.*/
+ EXTI_D1->IMR1 &= ~padmask;
+ EXTI_D1->EMR1 &= ~padmask;
+ EXTI->RTSR1 = rtsr1 & ~padmask;
+ EXTI->FTSR1 = ftsr1 & ~padmask;
+ EXTI_D1->PR1 = padmask;
+#else
+ /* Disabling channel.*/
+ EXTI->IMR1 &= ~padmask;
+ EXTI->EMR1 &= ~padmask;
+ EXTI->RTSR1 = rtsr1 & ~padmask;
+ EXTI->FTSR1 = ftsr1 & ~padmask;
+#if STM32_EXTI_SEPARATE_RF == FALSE
+ EXTI->PR1 = padmask;
+#else
+ EXTI->RPR1 = padmask;
+ EXTI->FPR1 = padmask;
+#endif
+#endif
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT
+ /* Callback cleared and/or thread reset.*/
+ _pal_clear_event(pad);
+#endif
+ }
+}
+#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h new file mode 100644 index 0000000..15b541b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/hal_pal_lld.h @@ -0,0 +1,514 @@ +/*
+ 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 GPIOv2/hal_pal_lld.h
+ * @brief STM32 PAL low level driver header.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#ifndef HAL_PAL_LLD_H
+#define HAL_PAL_LLD_H
+
+#include "stm32_gpio.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Unsupported modes and specific modes */
+/*===========================================================================*/
+
+/* Specifies palInit() without parameter, required until all platforms will
+ be updated to the new style.*/
+#define PAL_NEW_INIT
+
+#undef PAL_MODE_RESET
+#undef PAL_MODE_UNCONNECTED
+#undef PAL_MODE_INPUT
+#undef PAL_MODE_INPUT_PULLUP
+#undef PAL_MODE_INPUT_PULLDOWN
+#undef PAL_MODE_INPUT_ANALOG
+#undef PAL_MODE_OUTPUT_PUSHPULL
+#undef PAL_MODE_OUTPUT_OPENDRAIN
+
+/**
+ * @name STM32-specific I/O mode flags
+ * @{
+ */
+#define PAL_STM32_MODE_MASK (3U << 0U)
+#define PAL_STM32_MODE_INPUT (0U << 0U)
+#define PAL_STM32_MODE_OUTPUT (1U << 0U)
+#define PAL_STM32_MODE_ALTERNATE (2U << 0U)
+#define PAL_STM32_MODE_ANALOG (3U << 0U)
+
+#define PAL_STM32_OTYPE_MASK (1U << 2U)
+#define PAL_STM32_OTYPE_PUSHPULL (0U << 2U)
+#define PAL_STM32_OTYPE_OPENDRAIN (1U << 2U)
+
+#define PAL_STM32_OSPEED_MASK (3U << 3U)
+#define PAL_STM32_OSPEED_LOWEST (0U << 3U)
+#if defined(STM32F0XX) || defined(STM32F30X) || defined(STM32F37X)
+#define PAL_STM32_OSPEED_MID (1U << 3U)
+#else
+#define PAL_STM32_OSPEED_MID1 (1U << 3U)
+#define PAL_STM32_OSPEED_MID2 (2U << 3U)
+#endif
+#define PAL_STM32_OSPEED_HIGHEST (3U << 3U)
+
+#define PAL_STM32_PUPDR_MASK (3U << 5U)
+#define PAL_STM32_PUPDR_FLOATING (0U << 5U)
+#define PAL_STM32_PUPDR_PULLUP (1U << 5U)
+#define PAL_STM32_PUPDR_PULLDOWN (2U << 5U)
+
+#define PAL_STM32_ALTERNATE_MASK (15U << 7U)
+#define PAL_STM32_ALTERNATE(n) ((n) << 7U)
+
+/**
+ * @brief Alternate function.
+ *
+ * @param[in] n alternate function selector
+ */
+#define PAL_MODE_ALTERNATE(n) (PAL_STM32_MODE_ALTERNATE | \
+ PAL_STM32_ALTERNATE(n))
+/** @} */
+
+/**
+ * @name Standard I/O mode flags
+ * @{
+ */
+/**
+ * @brief Implemented as input.
+ */
+#define PAL_MODE_RESET PAL_STM32_MODE_INPUT
+
+/**
+ * @brief Implemented as input with pull-up.
+ */
+#define PAL_MODE_UNCONNECTED PAL_MODE_INPUT_PULLUP
+
+/**
+ * @brief Regular input high-Z pad.
+ */
+#define PAL_MODE_INPUT PAL_STM32_MODE_INPUT
+
+/**
+ * @brief Input pad with weak pull up resistor.
+ */
+#define PAL_MODE_INPUT_PULLUP (PAL_STM32_MODE_INPUT | \
+ PAL_STM32_PUPDR_PULLUP)
+
+/**
+ * @brief Input pad with weak pull down resistor.
+ */
+#define PAL_MODE_INPUT_PULLDOWN (PAL_STM32_MODE_INPUT | \
+ PAL_STM32_PUPDR_PULLDOWN)
+
+/**
+ * @brief Analog input mode.
+ */
+#define PAL_MODE_INPUT_ANALOG PAL_STM32_MODE_ANALOG
+
+/**
+ * @brief Push-pull output pad.
+ */
+#define PAL_MODE_OUTPUT_PUSHPULL (PAL_STM32_MODE_OUTPUT | \
+ PAL_STM32_OTYPE_PUSHPULL)
+
+/**
+ * @brief Open-drain output pad.
+ */
+#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_STM32_MODE_OUTPUT | \
+ PAL_STM32_OTYPE_OPENDRAIN)
+/** @} */
+
+/*===========================================================================*/
+/* I/O Ports Types and constants. */
+/*===========================================================================*/
+
+/**
+ * @name Port related definitions
+ * @{
+ */
+/**
+ * @brief Width, in bits, of an I/O port.
+ */
+#define PAL_IOPORTS_WIDTH 16
+
+/**
+ * @brief Whole port mask.
+ * @details This macro specifies all the valid bits into a port.
+ */
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
+/** @} */
+
+/**
+ * @name Line handling macros
+ * @{
+ */
+/**
+ * @brief Forms a line identifier.
+ * @details A port/pad pair are encoded into an @p ioline_t type. The encoding
+ * of this type is platform-dependent.
+ * @note In this driver the pad number is encoded in the lower 4 bits of
+ * the GPIO address which are guaranteed to be zero.
+ */
+#define PAL_LINE(port, pad) \
+ ((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad)))
+
+/**
+ * @brief Decodes a port identifier from a line identifier.
+ */
+#define PAL_PORT(line) \
+ ((stm32_gpio_t *)(((uint32_t)(line)) & 0xFFFFFFF0U))
+
+/**
+ * @brief Decodes a pad identifier from a line identifier.
+ */
+#define PAL_PAD(line) \
+ ((uint32_t)((uint32_t)(line) & 0x0000000FU))
+
+/**
+ * @brief Value identifying an invalid line.
+ */
+#define PAL_NOLINE 0U
+/** @} */
+
+/**
+ * @brief Type of digital I/O port sized unsigned integer.
+ */
+typedef uint32_t ioportmask_t;
+
+/**
+ * @brief Type of digital I/O modes.
+ */
+typedef uint32_t iomode_t;
+
+/**
+ * @brief Type of an I/O line.
+ */
+typedef uint32_t ioline_t;
+
+/**
+ * @brief Type of an event mode.
+ */
+typedef uint32_t ioeventmode_t;
+
+/**
+ * @brief Type of a port Identifier.
+ * @details This type can be a scalar or some kind of pointer, do not make
+ * any assumption about it, use the provided macros when populating
+ * variables of this type.
+ */
+typedef stm32_gpio_t * ioportid_t;
+
+/**
+ * @brief Type of an pad identifier.
+ */
+typedef uint32_t iopadid_t;
+
+/*===========================================================================*/
+/* I/O Ports Identifiers. */
+/* The low level driver wraps the definitions already present in the STM32 */
+/* firmware library. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO port A identifier.
+ */
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+#define IOPORT1 GPIOA
+#endif
+
+/**
+ * @brief GPIO port B identifier.
+ */
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+#define IOPORT2 GPIOB
+#endif
+
+/**
+ * @brief GPIO port C identifier.
+ */
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+#define IOPORT3 GPIOC
+#endif
+
+/**
+ * @brief GPIO port D identifier.
+ */
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+#define IOPORT4 GPIOD
+#endif
+
+/**
+ * @brief GPIO port E identifier.
+ */
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+#define IOPORT5 GPIOE
+#endif
+
+/**
+ * @brief GPIO port F identifier.
+ */
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+#define IOPORT6 GPIOF
+#endif
+
+/**
+ * @brief GPIO port G identifier.
+ */
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+#define IOPORT7 GPIOG
+#endif
+
+/**
+ * @brief GPIO port H identifier.
+ */
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+#define IOPORT8 GPIOH
+#endif
+
+/**
+ * @brief GPIO port I identifier.
+ */
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+#define IOPORT9 GPIOI
+#endif
+
+/**
+ * @brief GPIO port J identifier.
+ */
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+#define IOPORT10 GPIOJ
+#endif
+
+/**
+ * @brief GPIO port K identifier.
+ */
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+#define IOPORT11 GPIOK
+#endif
+
+/*===========================================================================*/
+/* Implementation, some of the following macros could be implemented as */
+/* functions, if so please put them in pal_lld.c. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO ports subsystem initialization.
+ *
+ * @notapi
+ */
+#define pal_lld_init() _pal_lld_init()
+
+/**
+ * @brief Reads an I/O port.
+ * @details This function is implemented by reading the GPIO IDR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The port bits.
+ *
+ * @notapi
+ */
+#define pal_lld_readport(port) ((ioportmask_t)((port)->IDR))
+
+/**
+ * @brief Reads the output latch.
+ * @details This function is implemented by reading the GPIO ODR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The latched logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readlatch(port) ((ioportmask_t)((port)->ODR))
+
+/**
+ * @brief Writes on a I/O port.
+ * @details This function is implemented by writing the GPIO ODR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be written on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_writeport(port, bits) ((port)->ODR = (uint32_t)(bits))
+
+/**
+ * @brief Sets a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be ORed on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_setport(port, bits) ((port)->BSRR.H.set = (uint16_t)(bits))
+
+/**
+ * @brief Clears a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be cleared on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_clearport(port, bits) ((port)->BSRR.H.clear = (uint16_t)(bits))
+
+/**
+ * @brief Writes a group of bits.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset the group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group
+ * width are masked.
+ *
+ * @notapi
+ */
+#define pal_lld_writegroup(port, mask, offset, bits) { \
+ uint32_t w = ((~(uint32_t)(bits) & (uint32_t)(mask)) << (16U + (offset))) | \
+ ((uint32_t)(bits) & (uint32_t)(mask)) << (offset); \
+ (port)->BSRR.W = w; \
+}
+
+/**
+ * @brief Pads group mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] mode group mode
+ *
+ * @notapi
+ */
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
+ _pal_lld_setgroupmode(port, mask << offset, mode)
+
+/**
+ * @brief Writes a logical state on an output pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] bit logical value, the value must be @p PAL_LOW or
+ * @p PAL_HIGH
+ *
+ * @notapi
+ */
+#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
+
+/**
+ * @brief Pad event enable.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad event mode
+ *
+ * @notapi
+ */
+#define pal_lld_enablepadevent(port, pad, mode) \
+ _pal_lld_enablepadevent(port, pad, mode)
+
+/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_disablepadevent(port, pad) \
+ _pal_lld_disablepadevent(port, pad)
+
+/**
+ * @brief Returns a PAL event structure associated to a pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_get_pad_event(port, pad) \
+ &_pal_events[pad]; (void)(port)
+
+/**
+ * @brief Returns a PAL event structure associated to a line.
+ *
+ * @param[in] line line identifier
+ *
+ * @notapi
+ */
+#define pal_lld_get_line_event(line) \
+ &_pal_events[PAL_PAD(line)]
+
+/**
+ * @brief Pad event enable check.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return Pad event status.
+ * @retval false if the pad event is disabled.
+ * @retval true if the pad event is enabled.
+ *
+ * @notapi
+ */
+#define pal_lld_ispadeventenabled(port, pad) \
+ (bool)((EXTI->IMR1 & (1U << (uint32_t)pad)) != 0U)
+
+#if !defined(__DOXYGEN__)
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE)
+extern palevent_t _pal_events[16];
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _pal_lld_init(void);
+ void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode);
+ void _pal_lld_enablepadevent(ioportid_t port,
+ iopadid_t pad,
+ ioeventmode_t mode);
+ void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PAL */
+
+#endif /* HAL_PAL_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h new file mode 100644 index 0000000..83fd51e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv2/stm32_gpio.h @@ -0,0 +1,111 @@ +/*
+ 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 GPIOv2/stm32_gpio.h
+ * @brief STM32 GPIO units common header.
+ * @note This file requires definitions from the ST STM32 header file.
+ *
+ * @addtogroup STM32_GPIOv2
+ * @{
+ */
+
+#ifndef STM32_GPIO_H
+#define STM32_GPIO_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/* Discarded definitions from the ST headers, the PAL driver uses its own
+ definitions in order to have an unified handling for all devices.
+ Unfortunately the ST headers have no uniform definitions for the same
+ objects across the various sub-families.*/
+#undef GPIOA
+#undef GPIOB
+#undef GPIOC
+#undef GPIOD
+#undef GPIOE
+#undef GPIOF
+#undef GPIOG
+#undef GPIOH
+#undef GPIOI
+#undef GPIOJ
+#undef GPIOK
+
+/**
+ * @name GPIO ports definitions
+ * @{
+ */
+#define GPIOA ((stm32_gpio_t *)GPIOA_BASE)
+#define GPIOB ((stm32_gpio_t *)GPIOB_BASE)
+#define GPIOC ((stm32_gpio_t *)GPIOC_BASE)
+#define GPIOD ((stm32_gpio_t *)GPIOD_BASE)
+#define GPIOE ((stm32_gpio_t *)GPIOE_BASE)
+#define GPIOF ((stm32_gpio_t *)GPIOF_BASE)
+#define GPIOG ((stm32_gpio_t *)GPIOG_BASE)
+#define GPIOH ((stm32_gpio_t *)GPIOH_BASE)
+#define GPIOI ((stm32_gpio_t *)GPIOI_BASE)
+#define GPIOJ ((stm32_gpio_t *)GPIOJ_BASE)
+#define GPIOK ((stm32_gpio_t *)GPIOK_BASE)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 GPIO registers block.
+ */
+typedef struct {
+
+ volatile uint32_t MODER;
+ volatile uint32_t OTYPER;
+ volatile uint32_t OSPEEDR;
+ volatile uint32_t PUPDR;
+ volatile uint32_t IDR;
+ volatile uint32_t ODR;
+ volatile union {
+ uint32_t W;
+ struct {
+ uint16_t set;
+ uint16_t clear;
+ } H;
+ } BSRR;
+ volatile uint32_t LOCKR;
+ volatile uint32_t AFRL;
+ volatile uint32_t AFRH;
+} stm32_gpio_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#endif /* STM32_GPIO_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk new file mode 100644 index 0000000..b2db0f3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv3
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c new file mode 100644 index 0000000..92b61b5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.c @@ -0,0 +1,249 @@ +/*
+ 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 GPIOv3/hal_pal_lld.c
+ * @brief STM32 PAL low level driver code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Event records for the 16 GPIO EXTI channels.
+ */
+palevent_t _pal_events[16];
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief PAL driver initialization.
+ *
+ * @notapi
+ */
+void _pal_lld_init(void) {
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+ unsigned i;
+
+ for (i = 0; i < 16; i++) {
+ _pal_init_event(i);
+ }
+#endif
+}
+
+/**
+ * @brief Pads mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note @p PAL_MODE_UNCONNECTED is implemented as push pull at minimum
+ * speed.
+ *
+ * @param[in] port the port identifier
+ * @param[in] mask the group mask
+ * @param[in] mode the mode
+ *
+ * @notapi
+ */
+void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode) {
+
+ uint32_t moder = (mode & PAL_STM32_MODE_MASK) >> 0;
+ uint32_t otyper = (mode & PAL_STM32_OTYPE_MASK) >> 2;
+ uint32_t ospeedr = (mode & PAL_STM32_OSPEED_MASK) >> 3;
+ uint32_t pupdr = (mode & PAL_STM32_PUPDR_MASK) >> 5;
+ uint32_t altr = (mode & PAL_STM32_ALTERNATE_MASK) >> 7;
+ uint32_t ascr = (mode & PAL_STM32_ASCR_MASK) >> 11;
+ uint32_t lockr = (mode & PAL_STM32_LOCKR_MASK) >> 12;
+ uint32_t bit = 0;
+ while (true) {
+ if ((mask & 1) != 0) {
+ uint32_t altrmask, m1, m2, m4;
+
+ altrmask = altr << ((bit & 7) * 4);
+ m1 = 1 << bit;
+ m2 = 3 << (bit * 2);
+ m4 = 15 << ((bit & 7) * 4);
+ port->OTYPER = (port->OTYPER & ~m1) | otyper;
+ port->ASCR = (port->ASCR & ~m1) | ascr;
+ port->OSPEEDR = (port->OSPEEDR & ~m2) | ospeedr;
+ port->PUPDR = (port->PUPDR & ~m2) | pupdr;
+ if ((mode & PAL_STM32_MODE_MASK) == PAL_STM32_MODE_ALTERNATE) {
+ /* If going in alternate mode then the alternate number is set
+ before switching mode in order to avoid glitches.*/
+ if (bit < 8)
+ port->AFRL = (port->AFRL & ~m4) | altrmask;
+ else
+ port->AFRH = (port->AFRH & ~m4) | altrmask;
+ port->MODER = (port->MODER & ~m2) | moder;
+ }
+ else {
+ /* If going into a non-alternate mode then the mode is switched
+ before setting the alternate mode in order to avoid glitches.*/
+ port->MODER = (port->MODER & ~m2) | moder;
+ if (bit < 8)
+ port->AFRL = (port->AFRL & ~m4) | altrmask;
+ else
+ port->AFRH = (port->AFRH & ~m4) | altrmask;
+ }
+ port->LOCKR = (port->LOCKR & ~m1) | lockr;
+ }
+ mask >>= 1;
+ if (!mask)
+ return;
+ otyper <<= 1;
+ ascr <<= 1;
+ ospeedr <<= 2;
+ pupdr <<= 2;
+ moder <<= 2;
+ bit++;
+ }
+}
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Pad event enable.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad event mode
+ *
+ * @notapi
+ */
+void _pal_lld_enablepadevent(ioportid_t port,
+ iopadid_t pad,
+ ioeventmode_t mode) {
+
+ uint32_t padmask, cridx, croff, crmask, portidx;
+
+ /* Mask of the pad.*/
+ padmask = 1U << (uint32_t)pad;
+
+ /* Multiple channel setting of the same channel not allowed, first disable
+ it. This is done because on STM32 the same channel cannot be mapped on
+ multiple ports.*/
+ osalDbgAssert(((EXTI->RTSR1 & padmask) == 0U) &&
+ ((EXTI->FTSR1 & padmask) == 0U), "channel already in use");
+
+ /* Index and mask of the SYSCFG CR register to be used.*/
+ cridx = (uint32_t)pad >> 2U;
+ croff = ((uint32_t)pad & 3U) * 4U;
+ crmask = ~(0xFU << croff);
+
+ /* Port index is obtained assuming that GPIO ports are placed at regular
+ 0x400 intervals in memory space. So far this is true for all devices.*/
+ portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU;
+
+ /* Port selection in SYSCFG.*/
+ SYSCFG->EXTICR[cridx] = (SYSCFG->EXTICR[cridx] & crmask) | (portidx << croff);
+
+ /* Programming edge registers.*/
+ if (mode & PAL_EVENT_MODE_RISING_EDGE)
+ EXTI->RTSR1 |= padmask;
+ else
+ EXTI->RTSR1 &= ~padmask;
+ if (mode & PAL_EVENT_MODE_FALLING_EDGE)
+ EXTI->FTSR1 |= padmask;
+ else
+ EXTI->FTSR1 &= ~padmask;
+
+ /* Programming interrupt and event registers.*/
+ EXTI->IMR1 |= padmask;
+ EXTI->EMR1 &= ~padmask;
+}
+
+/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) {
+ uint32_t padmask, rtsr1, ftsr1;
+
+ rtsr1 = EXTI->RTSR1;
+ ftsr1 = EXTI->FTSR1;
+
+ /* Mask of the pad.*/
+ padmask = 1U << (uint32_t)pad;
+
+ /* If either RTRS1 or FTSR1 is enabled then the channel is in use.*/
+ if (((rtsr1 | ftsr1) & padmask) != 0U) {
+ uint32_t cridx, croff, crport, portidx;
+
+ /* Index and mask of the SYSCFG CR register to be used.*/
+ cridx = (uint32_t)pad >> 2U;
+ croff = ((uint32_t)pad & 3U) * 4U;
+
+ /* Port index is obtained assuming that GPIO ports are placed at regular
+ 0x400 intervals in memory space. So far this is true for all devices.*/
+ portidx = (((uint32_t)port - (uint32_t)GPIOA) >> 10U) & 0xFU;
+
+ crport = (SYSCFG->EXTICR[cridx] >> croff) & 0xFU;
+
+ osalDbgAssert(crport == portidx, "channel mapped on different port");
+
+ /* Disabling channel.*/
+ EXTI->IMR1 &= ~padmask;
+ EXTI->EMR1 &= ~padmask;
+ EXTI->RTSR1 = rtsr1 & ~padmask;
+ EXTI->FTSR1 = ftsr1 & ~padmask;
+ EXTI->PR1 = padmask;
+
+#if PAL_USE_CALLBACKS || PAL_USE_WAIT
+ /* Callback cleared and/or thread reset.*/
+ _pal_clear_event(pad);
+#endif
+ }
+}
+#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h new file mode 100644 index 0000000..9824257 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/hal_pal_lld.h @@ -0,0 +1,554 @@ +/*
+ 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 GPIOv3/hal_pal_lld.h
+ * @brief STM32 PAL low level driver header.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#ifndef HAL_PAL_LLD_H
+#define HAL_PAL_LLD_H
+
+#include "stm32_gpio.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Unsupported modes and specific modes */
+/*===========================================================================*/
+
+/* Specifies palInit() without parameter, required until all platforms will
+ be updated to the new style.*/
+#define PAL_NEW_INIT
+
+#undef PAL_MODE_RESET
+#undef PAL_MODE_UNCONNECTED
+#undef PAL_MODE_INPUT
+#undef PAL_MODE_INPUT_PULLUP
+#undef PAL_MODE_INPUT_PULLDOWN
+#undef PAL_MODE_INPUT_ANALOG
+#undef PAL_MODE_OUTPUT_PUSHPULL
+#undef PAL_MODE_OUTPUT_OPENDRAIN
+
+/**
+ * @name STM32-specific I/O mode flags
+ * @{
+ */
+#define PAL_STM32_MODE_MASK (3U << 0U)
+#define PAL_STM32_MODE_INPUT (0U << 0U)
+#define PAL_STM32_MODE_OUTPUT (1U << 0U)
+#define PAL_STM32_MODE_ALTERNATE (2U << 0U)
+#define PAL_STM32_MODE_ANALOG (3U << 0U)
+
+#define PAL_STM32_OTYPE_MASK (1U << 2U)
+#define PAL_STM32_OTYPE_PUSHPULL (0U << 2U)
+#define PAL_STM32_OTYPE_OPENDRAIN (1U << 2U)
+
+#define PAL_STM32_OSPEED_MASK (3U << 3U)
+#define PAL_STM32_OSPEED_LOW (0U << 3U)
+#define PAL_STM32_OSPEED_MEDIUM (1U << 3U)
+#define PAL_STM32_OSPEED_FAST (2U << 3U)
+#define PAL_STM32_OSPEED_HIGH (3U << 3U)
+
+#define PAL_STM32_PUPDR_MASK (3U << 5U)
+#define PAL_STM32_PUPDR_FLOATING (0U << 5U)
+#define PAL_STM32_PUPDR_PULLUP (1U << 5U)
+#define PAL_STM32_PUPDR_PULLDOWN (2U << 5U)
+
+#define PAL_STM32_ALTERNATE_MASK (15U << 7U)
+#define PAL_STM32_ALTERNATE(n) ((n) << 7U)
+
+#define PAL_STM32_ASCR_MASK (1U << 11U)
+#define PAL_STM32_ASCR_OFF (0U << 11U)
+#define PAL_STM32_ASCR_ON (1U << 11U)
+
+#define PAL_STM32_LOCKR_MASK (1U << 12U)
+#define PAL_STM32_LOCKR_OFF (0U << 12U)
+#define PAL_STM32_LOCKR_ON (1U << 12U)
+
+/**
+ * @brief Alternate function.
+ *
+ * @param[in] n alternate function selector
+ */
+#define PAL_MODE_ALTERNATE(n) (PAL_STM32_MODE_ALTERNATE | \
+ PAL_STM32_ALTERNATE(n))
+/** @} */
+
+/**
+ * @name Standard I/O mode flags
+ * @{
+ */
+/**
+ * @brief Implemented as input.
+ */
+#define PAL_MODE_RESET PAL_STM32_MODE_INPUT
+
+/**
+ * @brief Implemented as analog with analog switch disabled and lock.
+ */
+#define PAL_MODE_UNCONNECTED (PAL_STM32_MODE_ANALOG | \
+ PAL_STM32_ASCR_OFF | \
+ PAL_STM32_LOCKR_ON)
+
+/**
+ * @brief Regular input high-Z pad.
+ */
+#define PAL_MODE_INPUT PAL_STM32_MODE_INPUT
+
+/**
+ * @brief Input pad with weak pull up resistor.
+ */
+#define PAL_MODE_INPUT_PULLUP (PAL_STM32_MODE_INPUT | \
+ PAL_STM32_PUPDR_PULLUP)
+
+/**
+ * @brief Input pad with weak pull down resistor.
+ */
+#define PAL_MODE_INPUT_PULLDOWN (PAL_STM32_MODE_INPUT | \
+ PAL_STM32_PUPDR_PULLDOWN)
+
+/**
+ * @brief Analog input mode.
+ */
+#define PAL_MODE_INPUT_ANALOG (PAL_STM32_MODE_ANALOG | \
+ PAL_STM32_ASCR_ON)
+
+/**
+ * @brief Push-pull output pad.
+ */
+#define PAL_MODE_OUTPUT_PUSHPULL (PAL_STM32_MODE_OUTPUT | \
+ PAL_STM32_OTYPE_PUSHPULL)
+
+/**
+ * @brief Open-drain output pad.
+ */
+#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_STM32_MODE_OUTPUT | \
+ PAL_STM32_OTYPE_OPENDRAIN)
+/** @} */
+
+/* Discarded definitions from the ST headers, the PAL driver uses its own
+ definitions in order to have an unified handling for all devices.
+ Unfortunately the ST headers have no uniform definitions for the same
+ objects across the various sub-families.*/
+#undef GPIOA
+#undef GPIOB
+#undef GPIOC
+#undef GPIOD
+#undef GPIOE
+#undef GPIOF
+#undef GPIOG
+#undef GPIOH
+#undef GPIOI
+#undef GPIOJ
+#undef GPIOK
+
+/**
+ * @name GPIO ports definitions
+ * @{
+ */
+#define GPIOA ((stm32_gpio_t *)GPIOA_BASE)
+#define GPIOB ((stm32_gpio_t *)GPIOB_BASE)
+#define GPIOC ((stm32_gpio_t *)GPIOC_BASE)
+#define GPIOD ((stm32_gpio_t *)GPIOD_BASE)
+#define GPIOE ((stm32_gpio_t *)GPIOE_BASE)
+#define GPIOF ((stm32_gpio_t *)GPIOF_BASE)
+#define GPIOG ((stm32_gpio_t *)GPIOG_BASE)
+#define GPIOH ((stm32_gpio_t *)GPIOH_BASE)
+#define GPIOI ((stm32_gpio_t *)GPIOI_BASE)
+#define GPIOJ ((stm32_gpio_t *)GPIOJ_BASE)
+#define GPIOK ((stm32_gpio_t *)GPIOK_BASE)
+/** @} */
+
+/*===========================================================================*/
+/* I/O Ports Types and constants. */
+/*===========================================================================*/
+
+/**
+ * @name Port related definitions
+ * @{
+ */
+/**
+ * @brief Width, in bits, of an I/O port.
+ */
+#define PAL_IOPORTS_WIDTH 16
+
+/**
+ * @brief Whole port mask.
+ * @details This macro specifies all the valid bits into a port.
+ */
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
+/** @} */
+
+/**
+ * @name Line handling macros
+ * @{
+ */
+/**
+ * @brief Forms a line identifier.
+ * @details A port/pad pair are encoded into an @p ioline_t type. The encoding
+ * of this type is platform-dependent.
+ * @note In this driver the pad number is encoded in the lower 4 bits of
+ * the GPIO address which are guaranteed to be zero.
+ */
+#define PAL_LINE(port, pad) \
+ ((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad)))
+
+/**
+ * @brief Decodes a port identifier from a line identifier.
+ */
+#define PAL_PORT(line) \
+ ((stm32_gpio_t *)(((uint32_t)(line)) & 0xFFFFFFF0U))
+
+/**
+ * @brief Decodes a pad identifier from a line identifier.
+ */
+#define PAL_PAD(line) \
+ ((uint32_t)((uint32_t)(line) & 0x0000000FU))
+
+/**
+ * @brief Value identifying an invalid line.
+ */
+#define PAL_NOLINE 0U
+/** @} */
+
+/**
+ * @brief Type of digital I/O port sized unsigned integer.
+ */
+typedef uint32_t ioportmask_t;
+
+/**
+ * @brief Type of digital I/O modes.
+ */
+typedef uint32_t iomode_t;
+
+/**
+ * @brief Type of an I/O line.
+ */
+typedef uint32_t ioline_t;
+
+/**
+ * @brief Type of an event mode.
+ */
+typedef uint32_t ioeventmode_t;
+
+/**
+ * @brief Type of a port Identifier.
+ * @details This type can be a scalar or some kind of pointer, do not make
+ * any assumption about it, use the provided macros when populating
+ * variables of this type.
+ */
+typedef stm32_gpio_t * ioportid_t;
+
+/**
+ * @brief Type of an pad identifier.
+ */
+typedef uint32_t iopadid_t;
+
+/*===========================================================================*/
+/* I/O Ports Identifiers. */
+/* The low level driver wraps the definitions already present in the STM32 */
+/* firmware library. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO port A identifier.
+ */
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+#define IOPORT1 GPIOA
+#endif
+
+/**
+ * @brief GPIO port B identifier.
+ */
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+#define IOPORT2 GPIOB
+#endif
+
+/**
+ * @brief GPIO port C identifier.
+ */
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+#define IOPORT3 GPIOC
+#endif
+
+/**
+ * @brief GPIO port D identifier.
+ */
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+#define IOPORT4 GPIOD
+#endif
+
+/**
+ * @brief GPIO port E identifier.
+ */
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+#define IOPORT5 GPIOE
+#endif
+
+/**
+ * @brief GPIO port F identifier.
+ */
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+#define IOPORT6 GPIOF
+#endif
+
+/**
+ * @brief GPIO port G identifier.
+ */
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+#define IOPORT7 GPIOG
+#endif
+
+/**
+ * @brief GPIO port H identifier.
+ */
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+#define IOPORT8 GPIOH
+#endif
+
+/**
+ * @brief GPIO port I identifier.
+ */
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+#define IOPORT9 GPIOI
+#endif
+
+/**
+ * @brief GPIO port J identifier.
+ */
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+#define IOPORT10 GPIOJ
+#endif
+
+/**
+ * @brief GPIO port K identifier.
+ */
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+#define IOPORT11 GPIOK
+#endif
+
+/*===========================================================================*/
+/* Implementation, some of the following macros could be implemented as */
+/* functions, if so please put them in pal_lld.c. */
+/*===========================================================================*/
+
+/**
+ * @brief GPIO ports subsystem initialization.
+ *
+ * @notapi
+ */
+#define pal_lld_init() _pal_lld_init()
+
+/**
+ * @brief Reads an I/O port.
+ * @details This function is implemented by reading the GPIO IDR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The port bits.
+ *
+ * @notapi
+ */
+#define pal_lld_readport(port) ((ioportmask_t)((port)->IDR))
+
+/**
+ * @brief Reads the output latch.
+ * @details This function is implemented by reading the GPIO ODR register, the
+ * implementation has no side effects.
+ * @note This function is not meant to be invoked directly by the application
+ * code.
+ *
+ * @param[in] port port identifier
+ * @return The latched logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readlatch(port) ((ioportmask_t)((port)->ODR))
+
+/**
+ * @brief Writes on a I/O port.
+ * @details This function is implemented by writing the GPIO ODR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be written on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_writeport(port, bits) ((port)->ODR = (uint32_t)(bits))
+
+/**
+ * @brief Sets a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be ORed on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_setport(port, bits) ((port)->BSRR.H.set = (uint16_t)(bits))
+
+/**
+ * @brief Clears a bits mask on a I/O port.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be cleared on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_clearport(port, bits) ((port)->BSRR.H.clear = (uint16_t)(bits))
+
+/**
+ * @brief Writes a group of bits.
+ * @details This function is implemented by writing the GPIO BSRR register, the
+ * implementation has no side effects.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset the group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group
+ * width are masked.
+ *
+ * @notapi
+ */
+#define pal_lld_writegroup(port, mask, offset, bits) { \
+ uint32_t w = ((~(uint32_t)(bits) & (uint32_t)(mask)) << (16U + (offset))) | \
+ ((uint32_t)(bits) & (uint32_t)(mask)) << (offset); \
+ (port)->BSRR.W = w; \
+}
+
+/**
+ * @brief Pads group mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] mode group mode
+ *
+ * @notapi
+ */
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
+ _pal_lld_setgroupmode(port, mask << offset, mode)
+
+/**
+ * @brief Writes a logical state on an output pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] bit logical value, the value must be @p PAL_LOW or
+ * @p PAL_HIGH
+ *
+ * @notapi
+ */
+#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
+
+/**
+ * @brief Pad event enable.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad event mode
+ *
+ * @notapi
+ */
+#define pal_lld_enablepadevent(port, pad, mode) \
+ _pal_lld_enablepadevent(port, pad, mode)
+
+/**
+ * @brief Pad event disable.
+ * @details This function disables previously programmed event callbacks.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_disablepadevent(port, pad) \
+ _pal_lld_disablepadevent(port, pad)
+
+/**
+ * @brief Returns a PAL event structure associated to a pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_get_pad_event(port, pad) \
+ &_pal_events[pad]; (void)(port)
+
+/**
+ * @brief Returns a PAL event structure associated to a line.
+ *
+ * @param[in] line line identifier
+ *
+ * @notapi
+ */
+#define pal_lld_get_line_event(line) \
+ &_pal_events[PAL_PAD(line)]
+
+/**
+ * @brief Pad event enable check.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return Pad event status.
+ * @retval false if the pad event is disabled.
+ * @retval true if the pad event is enabled.
+ *
+ * @notapi
+ */
+#define pal_lld_ispadeventenabled(port, pad) \
+ (bool)((EXTI->IMR1 & (1U << (uint32_t)pad)) != 0U)
+
+#if !defined(__DOXYGEN__)
+#if (PAL_USE_WAIT == TRUE) || (PAL_USE_CALLBACKS == TRUE)
+extern palevent_t _pal_events[16];
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _pal_lld_init(void);
+ void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode);
+ void _pal_lld_enablepadevent(ioportid_t port,
+ iopadid_t pad,
+ ioeventmode_t mode);
+ void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PAL */
+
+#endif /* HAL_PAL_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h new file mode 100644 index 0000000..c8ce1df --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/GPIOv3/stm32_gpio.h @@ -0,0 +1,113 @@ +/*
+ 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 GPIOv3/stm32_gpio.h
+ * @brief STM32 GPIO units common header.
+ * @note This file requires definitions from the ST STM32 header file.
+ *
+ * @addtogroup STM32_GPIOv3
+ * @{
+ */
+
+#ifndef STM32_GPIO_H
+#define STM32_GPIO_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/* Discarded definitions from the ST headers, the PAL driver uses its own
+ definitions in order to have an unified handling for all devices.
+ Unfortunately the ST headers have no uniform definitions for the same
+ objects across the various sub-families.*/
+#undef GPIOA
+#undef GPIOB
+#undef GPIOC
+#undef GPIOD
+#undef GPIOE
+#undef GPIOF
+#undef GPIOG
+#undef GPIOH
+#undef GPIOI
+#undef GPIOJ
+#undef GPIOK
+
+/**
+ * @name GPIO ports definitions
+ * @{
+ */
+#define GPIOA ((stm32_gpio_t *)GPIOA_BASE)
+#define GPIOB ((stm32_gpio_t *)GPIOB_BASE)
+#define GPIOC ((stm32_gpio_t *)GPIOC_BASE)
+#define GPIOD ((stm32_gpio_t *)GPIOD_BASE)
+#define GPIOE ((stm32_gpio_t *)GPIOE_BASE)
+#define GPIOF ((stm32_gpio_t *)GPIOF_BASE)
+#define GPIOG ((stm32_gpio_t *)GPIOG_BASE)
+#define GPIOH ((stm32_gpio_t *)GPIOH_BASE)
+#define GPIOI ((stm32_gpio_t *)GPIOI_BASE)
+#define GPIOJ ((stm32_gpio_t *)GPIOJ_BASE)
+#define GPIOK ((stm32_gpio_t *)GPIOK_BASE)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 GPIO registers block.
+ */
+typedef struct {
+
+ volatile uint32_t MODER;
+ volatile uint32_t OTYPER;
+ volatile uint32_t OSPEEDR;
+ volatile uint32_t PUPDR;
+ volatile uint32_t IDR;
+ volatile uint32_t ODR;
+ volatile union {
+ uint32_t W;
+ struct {
+ uint16_t set;
+ uint16_t clear;
+ } H;
+ } BSRR;
+ volatile uint32_t LOCKR;
+ volatile uint32_t AFRL;
+ volatile uint32_t AFRH;
+ volatile uint32_t BRR;
+ volatile uint32_t ASCR;
+} stm32_gpio_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#endif /* STM32_GPIO_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk new file mode 100644 index 0000000..476dcb8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes)
+ # Fallback SW driver.
+ ifeq ($(USE_SMART_BUILD),yes)
+ ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+ PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+ endif
+ else
+ PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+ endif
+ PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C
+else
+ # Default HW driver.
+ ifeq ($(USE_SMART_BUILD),yes)
+ ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
+ endif
+ else
+ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
+ endif
+ PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1
+endif
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c new file mode 100644 index 0000000..3fc2289 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c @@ -0,0 +1,889 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file I2Cv1/hal_i2c_lld.c
+ * @brief STM32 I2C subsystem low level driver source.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define I2C1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \
+ STM32_I2C1_RX_DMA_CHN)
+
+#define I2C1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \
+ STM32_I2C1_TX_DMA_CHN)
+
+#define I2C2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \
+ STM32_I2C2_RX_DMA_CHN)
+
+#define I2C2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \
+ STM32_I2C2_TX_DMA_CHN)
+
+#define I2C3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \
+ STM32_I2C3_RX_DMA_CHN)
+
+#define I2C3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \
+ STM32_I2C3_TX_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define I2C_EV5_MASTER_MODE_SELECT \
+ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_SB))
+
+#define I2C_EV5_MASTER_MODE_SELECT_NO_BUSY \
+ ((uint32_t)((I2C_SR2_MSL << 16) | I2C_SR1_SB))
+
+#define I2C_EV6_MASTER_TRA_MODE_SELECTED \
+ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \
+ I2C_SR1_ADDR | I2C_SR1_TXE))
+
+#define I2C_EV6_MASTER_REC_MODE_SELECTED \
+ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
+
+#define I2C_EV8_2_MASTER_BYTE_TRANSMITTED \
+ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \
+ I2C_SR1_BTF | I2C_SR1_TXE))
+
+#define I2C_EV9_MASTER_ADD10 \
+ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_ADD10))
+
+#define I2C_EV_MASK 0x00FFFFFF
+
+#define I2C_ERROR_MASK \
+ ((uint16_t)(I2C_SR1_BERR | I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_OVR | \
+ I2C_SR1_PECERR | I2C_SR1_TIMEOUT | I2C_SR1_SMBALERT))
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief I2C1 driver identifier.*/
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+I2CDriver I2CD1;
+#endif
+
+/** @brief I2C2 driver identifier.*/
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+I2CDriver I2CD2;
+#endif
+
+/** @brief I2C3 driver identifier.*/
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+I2CDriver I2CD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Aborts an I2C transaction.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_abort_operation(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Stops the I2C peripheral.*/
+ dp->CR1 = I2C_CR1_SWRST;
+ dp->CR1 = 0;
+ dp->CR2 = 0;
+ dp->SR1 = 0;
+
+ /* Stops the associated DMA streams.*/
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+}
+
+/**
+ * @brief Set clock speed.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_set_clock(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ uint16_t regCCR, clock_div;
+ int32_t clock_speed = i2cp->config->clock_speed;
+ i2cdutycycle_t duty = i2cp->config->duty_cycle;
+
+ osalDbgCheck((i2cp != NULL) &&
+ (clock_speed > 0) &&
+ (clock_speed <= 400000));
+
+ /* CR2 Configuration.*/
+ dp->CR2 &= (uint16_t)~I2C_CR2_FREQ;
+ dp->CR2 |= (uint16_t)I2C_CLK_FREQ;
+
+ /* CCR Configuration.*/
+ regCCR = 0;
+ clock_div = I2C_CCR_CCR;
+
+ if (clock_speed <= 100000) {
+ /* Configure clock_div in standard mode.*/
+ osalDbgAssert(duty == STD_DUTY_CYCLE, "invalid standard mode duty cycle");
+
+ /* Standard mode clock_div calculate: Tlow/Thigh = 1/1.*/
+ osalDbgAssert((STM32_PCLK1 % (clock_speed * 2)) == 0,
+ "PCLK1 must be divisible without remainder");
+ clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 2));
+
+ osalDbgAssert(clock_div >= 0x04,
+ "clock divider less then 0x04 not allowed");
+ regCCR |= (clock_div & I2C_CCR_CCR);
+
+ /* Sets the Maximum Rise Time for standard mode.*/
+ dp->TRISE = I2C_CLK_FREQ + 1;
+ }
+ else if (clock_speed <= 400000) {
+ /* Configure clock_div in fast mode.*/
+ osalDbgAssert((duty == FAST_DUTY_CYCLE_2) ||
+ (duty == FAST_DUTY_CYCLE_16_9),
+ "invalid fast mode duty cycle");
+
+ if (duty == FAST_DUTY_CYCLE_2) {
+ /* Fast mode clock_div calculate: Tlow/Thigh = 2/1.*/
+ osalDbgAssert((STM32_PCLK1 % (clock_speed * 3)) == 0,
+ "PCLK1 must be divided without remainder");
+ clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 3));
+ }
+ else if (duty == FAST_DUTY_CYCLE_16_9) {
+ /* Fast mode clock_div calculate: Tlow/Thigh = 16/9.*/
+ osalDbgAssert((STM32_PCLK1 % (clock_speed * 25)) == 0,
+ "PCLK1 must be divided without remainder");
+ clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 25));
+ regCCR |= I2C_CCR_DUTY;
+ }
+
+ osalDbgAssert(clock_div >= 0x01,
+ "clock divider less then 0x04 not allowed");
+ regCCR |= (I2C_CCR_FS | (clock_div & I2C_CCR_CCR));
+
+ /* Sets the Maximum Rise Time for fast mode.*/
+ dp->TRISE = (I2C_CLK_FREQ * 300 / 1000) + 1;
+ }
+
+ osalDbgAssert((clock_div <= I2C_CCR_CCR), "the selected clock is too low");
+
+ dp->CCR = regCCR;
+}
+
+/**
+ * @brief Set operation mode of I2C hardware.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_set_opmode(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ i2copmode_t opmode = i2cp->config->op_mode;
+ uint16_t regCR1;
+
+ regCR1 = dp->CR1;
+ switch (opmode) {
+ case OPMODE_I2C:
+ regCR1 &= (uint16_t)~(I2C_CR1_SMBUS|I2C_CR1_SMBTYPE);
+ break;
+ case OPMODE_SMBUS_DEVICE:
+ regCR1 |= I2C_CR1_SMBUS;
+ regCR1 &= (uint16_t)~(I2C_CR1_SMBTYPE);
+ break;
+ case OPMODE_SMBUS_HOST:
+ regCR1 |= (I2C_CR1_SMBUS|I2C_CR1_SMBTYPE);
+ break;
+ }
+ dp->CR1 = regCR1;
+}
+
+/**
+ * @brief I2C shared ISR code.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ uint32_t regSR2 = dp->SR2;
+ uint32_t event = dp->SR1;
+
+ /* Interrupts are disabled just before dmaStreamEnable() because there
+ is no need of interrupts until next transaction begin. All the work is
+ done by the DMA.*/
+ switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
+ case I2C_EV5_MASTER_MODE_SELECT:
+ case I2C_EV5_MASTER_MODE_SELECT_NO_BUSY:
+ if ((i2cp->addr >> 8) > 0) {
+ /* 10-bit address: 1 1 1 1 0 X X R/W */
+ dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
+ } else {
+ dp->DR = i2cp->addr;
+ }
+ break;
+ case I2C_EV9_MASTER_ADD10:
+ /* Set second addr byte (10-bit addressing)*/
+ dp->DR = (0xFF & (i2cp->addr >> 1));
+ break;
+ case I2C_EV6_MASTER_REC_MODE_SELECTED:
+ dp->CR2 &= ~I2C_CR2_ITEVTEN;
+ dmaStreamEnable(i2cp->dmarx);
+ dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */
+ if (dmaStreamGetTransactionSize(i2cp->dmarx) < 2)
+ dp->CR1 &= ~I2C_CR1_ACK;
+ break;
+ case I2C_EV6_MASTER_TRA_MODE_SELECTED:
+ dp->CR2 &= ~I2C_CR2_ITEVTEN;
+ dmaStreamEnable(i2cp->dmatx);
+ break;
+ case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
+ /* Catches BTF event after the end of transmission.*/
+ (void)dp->DR; /* clear BTF.*/
+ if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) {
+ /* Starts "read after write" operation, LSB = 1 -> receive.*/
+ i2cp->addr |= 0x01;
+ dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
+ return;
+ }
+ dp->CR2 &= ~I2C_CR2_ITEVTEN;
+ dp->CR1 |= I2C_CR1_STOP;
+ _i2c_wakeup_isr(i2cp);
+ break;
+ default:
+ break;
+ }
+ /* Clear ADDR flag. */
+ if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
+ (void)dp->SR2;
+
+ /* Errata 2.4.6 for STM32F40x, Spurious Bus Error detection in Master mode.*/
+ if (event & I2C_SR1_BERR) {
+ dp->SR1 &= ~I2C_SR1_BERR;
+ }
+}
+
+/**
+ * @brief DMA RX end IRQ handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* DMA errors handling.*/
+#if defined(STM32_I2C_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_I2C_DMA_ERROR_HOOK(i2cp);
+ }
+#else
+ (void)flags;
+#endif
+
+ dmaStreamDisable(i2cp->dmarx);
+
+ dp->CR2 &= ~I2C_CR2_LAST;
+ dp->CR1 &= ~I2C_CR1_ACK;
+ dp->CR1 |= I2C_CR1_STOP;
+ _i2c_wakeup_isr(i2cp);
+}
+
+/**
+ * @brief DMA TX end IRQ handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* DMA errors handling.*/
+#if defined(STM32_I2C_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_I2C_DMA_ERROR_HOOK(i2cp);
+ }
+#else
+ (void)flags;
+#endif
+
+ dmaStreamDisable(i2cp->dmatx);
+ /* Enables interrupts to catch BTF event meaning transmission part complete.
+ Interrupt handler will decide to generate STOP or to begin receiving part
+ of R/W transaction itself.*/
+ dp->CR2 |= I2C_CR2_ITEVTEN;
+}
+
+/**
+ * @brief I2C error handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] sr content of the SR1 register to be decoded
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
+
+ /* Clears interrupt flags just to be safe.*/
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+
+ i2cp->errors = I2C_NO_ERROR;
+
+ if (sr & I2C_SR1_BERR) { /* Bus error. */
+ i2cp->errors |= I2C_BUS_ERROR;
+ /* Errata 2.4.6 for STM32F40x, Spurious Bus Error detection in
+ Master mode.*/
+ i2cp->i2c->SR1 &= ~I2C_SR1_BERR;
+ }
+
+ if (sr & I2C_SR1_ARLO) /* Arbitration lost. */
+ i2cp->errors |= I2C_ARBITRATION_LOST;
+
+ if (sr & I2C_SR1_AF) { /* Acknowledge fail. */
+ i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN;
+ i2cp->i2c->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */
+ i2cp->errors |= I2C_ACK_FAILURE;
+ }
+
+ if (sr & I2C_SR1_OVR) /* Overrun. */
+ i2cp->errors |= I2C_OVERRUN;
+
+ if (sr & I2C_SR1_TIMEOUT) /* SMBus Timeout. */
+ i2cp->errors |= I2C_TIMEOUT;
+
+ if (sr & I2C_SR1_PECERR) /* PEC error. */
+ i2cp->errors |= I2C_PEC_ERROR;
+
+ if (sr & I2C_SR1_SMBALERT) /* SMBus alert. */
+ i2cp->errors |= I2C_SMB_ALERT;
+
+ /* If some error has been identified then sends wakes the waiting thread.*/
+ if (i2cp->errors != I2C_NO_ERROR)
+ _i2c_wakeup_error_isr(i2cp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+/**
+ * @brief I2C1 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ i2c_lld_serve_event_interrupt(&I2CD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief I2C1 error interrupt handler.
+ */
+OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) {
+ uint16_t sr = I2CD1.i2c->SR1;
+
+ OSAL_IRQ_PROLOGUE();
+
+ I2CD1.i2c->SR1 = ~(sr & I2C_ERROR_MASK);
+ i2c_lld_serve_error_interrupt(&I2CD1, sr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+/**
+ * @brief I2C2 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ i2c_lld_serve_event_interrupt(&I2CD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief I2C2 error interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) {
+ uint16_t sr = I2CD2.i2c->SR1;
+
+ OSAL_IRQ_PROLOGUE();
+
+ I2CD2.i2c->SR1 = ~(sr & I2C_ERROR_MASK);
+ i2c_lld_serve_error_interrupt(&I2CD2, sr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+/**
+ * @brief I2C3 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ i2c_lld_serve_event_interrupt(&I2CD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief I2C3 error interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) {
+ uint16_t sr = I2CD3.i2c->SR1;
+
+ OSAL_IRQ_PROLOGUE();
+
+ I2CD3.i2c->SR1 = ~(sr & I2C_ERROR_MASK);
+ i2c_lld_serve_error_interrupt(&I2CD3, sr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_I2C_USE_I2C3 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level I2C driver initialization.
+ *
+ * @notapi
+ */
+void i2c_lld_init(void) {
+
+#if STM32_I2C_USE_I2C1
+ i2cObjectInit(&I2CD1);
+ I2CD1.thread = NULL;
+ I2CD1.i2c = I2C1;
+ I2CD1.dmarx = NULL;
+ I2CD1.dmatx = NULL;
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2
+ i2cObjectInit(&I2CD2);
+ I2CD2.thread = NULL;
+ I2CD2.i2c = I2C2;
+ I2CD2.dmarx = NULL;
+ I2CD2.dmatx = NULL;
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ i2cObjectInit(&I2CD3);
+ I2CD3.thread = NULL;
+ I2CD3.i2c = I2C3;
+ I2CD3.dmarx = NULL;
+ I2CD3.dmatx = NULL;
+#endif /* STM32_I2C_USE_I2C3 */
+}
+
+/**
+ * @brief Configures and activates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_start(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* If in stopped state then enables the I2C and DMA clocks.*/
+ if (i2cp->state == I2C_STOP) {
+
+ i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DIR_M2P;
+ i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DIR_P2M;
+
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ rccResetI2C1();
+
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C1_TX_DMA_STREAM,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableI2C1(true);
+ nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
+ nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+ }
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+ rccResetI2C2();
+
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C2_TX_DMA_STREAM,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableI2C2(true);
+ nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
+ nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+ }
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+ rccResetI2C3();
+
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C3_TX_DMA_STREAM,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableI2C3(true);
+ nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
+ nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+ }
+#endif /* STM32_I2C_USE_I2C3 */
+ }
+
+ /* I2C registers pointed by the DMA.*/
+ dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
+ dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
+
+ /* Reset i2c peripheral.*/
+ dp->CR1 = I2C_CR1_SWRST;
+ dp->CR1 = 0;
+ dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
+
+ /* Setup I2C parameters.*/
+ i2c_lld_set_clock(i2cp);
+ i2c_lld_set_opmode(i2cp);
+
+ /* Ready to go.*/
+ dp->CR1 |= I2C_CR1_PE;
+}
+
+/**
+ * @brief Deactivates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_stop(I2CDriver *i2cp) {
+
+ /* If not in stopped state then disables the I2C clock.*/
+ if (i2cp->state != I2C_STOP) {
+
+ /* I2C disable.*/
+ i2c_lld_abort_operation(i2cp);
+ dmaStreamFreeI(i2cp->dmatx);
+ dmaStreamFreeI(i2cp->dmarx);
+ i2cp->dmatx = NULL;
+ i2cp->dmarx = NULL;
+
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ nvicDisableVector(I2C1_EV_IRQn);
+ nvicDisableVector(I2C1_ER_IRQn);
+ rccDisableI2C1();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+ nvicDisableVector(I2C2_EV_IRQn);
+ nvicDisableVector(I2C2_ER_IRQn);
+ rccDisableI2C2();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+ nvicDisableVector(I2C3_EV_IRQn);
+ nvicDisableVector(I2C3_ER_IRQn);
+ rccDisableI2C3();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Receives data via the I2C bus as master.
+ * @details Number of receiving bytes must be more than 1 on STM32F1x. This is
+ * hardware restriction.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ systime_t start, end;
+ msg_t msg;
+
+#if defined(STM32F1XX_I2C)
+ osalDbgCheck(rxbytes > 1);
+#endif
+
+ /* Resetting error flags for this transfer.*/
+ i2cp->errors = I2C_NO_ERROR;
+
+ /* Initializes driver fields, LSB = 1 -> receive.*/
+ i2cp->addr = (addr << 1) | 0x01;
+
+ /* Releases the lock from high level driver.*/
+ osalSysUnlock();
+
+ /* RX DMA setup.*/
+ dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+ dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
+
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT));
+
+ /* Waits until BUSY flag is reset or, alternatively, for a timeout
+ condition.*/
+ while (true) {
+ osalSysLock();
+
+ /* If the bus is not busy then the operation can continue, note, the
+ loop is exited in the locked state.*/
+ if (!(dp->SR2 & I2C_SR2_BUSY) && !(dp->CR1 & I2C_CR1_STOP))
+ break;
+
+ /* If the system time went outside the allowed window then a timeout
+ condition is returned.*/
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ dmaStreamDisable(i2cp->dmarx);
+ return MSG_TIMEOUT;
+ }
+
+ osalSysUnlock();
+ }
+
+ /* Starts the operation.*/
+ dp->CR2 |= I2C_CR2_ITEVTEN;
+ dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
+
+ /* Waits for the operation completion or a timeout.*/
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+ if (msg != MSG_OK) {
+ dmaStreamDisable(i2cp->dmarx);
+ }
+
+ return msg;
+}
+
+/**
+ * @brief Transmits data via the I2C bus as master.
+ * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x.
+ * This is hardware restriction.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ systime_t start, end;
+ msg_t msg;
+
+#if defined(STM32F1XX_I2C)
+ osalDbgCheck((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL)));
+#endif
+
+ /* Resetting error flags for this transfer.*/
+ i2cp->errors = I2C_NO_ERROR;
+
+ /* Initializes driver fields, LSB = 0 -> transmit.*/
+ i2cp->addr = (addr << 1);
+
+ /* Releases the lock from high level driver.*/
+ osalSysUnlock();
+
+ /* TX DMA setup.*/
+ dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
+ dmaStreamSetMemory0(i2cp->dmatx, txbuf);
+ dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
+
+ /* RX DMA setup.*/
+ dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+ dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
+
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT));
+
+ /* Waits until BUSY flag is reset or, alternatively, for a timeout
+ condition.*/
+ while (true) {
+ osalSysLock();
+
+ /* If the bus is not busy then the operation can continue, note, the
+ loop is exited in the locked state.*/
+ if (!(dp->SR2 & I2C_SR2_BUSY) && !(dp->CR1 & I2C_CR1_STOP))
+ break;
+
+ /* If the system time went outside the allowed window then a timeout
+ condition is returned.*/
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+ return MSG_TIMEOUT;
+ }
+
+ osalSysUnlock();
+ }
+
+ /* Starts the operation.*/
+ dp->CR2 |= I2C_CR2_ITEVTEN;
+ dp->CR1 |= I2C_CR1_START;
+
+ /* Waits for the operation completion or a timeout.*/
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+ if (msg != MSG_OK) {
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+ }
+
+ return msg;
+}
+
+#endif /* HAL_USE_I2C */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h new file mode 100644 index 0000000..1328d47 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h @@ -0,0 +1,513 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file I2Cv1/hal_i2c_lld.h
+ * @brief STM32 I2C subsystem low level driver header.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#ifndef HAL_I2C_LLD_H
+#define HAL_I2C_LLD_H
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Peripheral clock frequency.
+ */
+#define I2C_CLK_FREQ ((STM32_PCLK1) / 1000000)
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief I2C1 driver enable switch.
+ * @details If set to @p TRUE the support for I2C1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C1 FALSE
+#endif
+
+/**
+ * @brief I2C2 driver enable switch.
+ * @details If set to @p TRUE the support for I2C2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C2 FALSE
+#endif
+
+/**
+ * @brief I2C3 driver enable switch.
+ * @details If set to @p TRUE the support for I2C3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C3 FALSE
+#endif
+
+/**
+ * @brief I2C timeout on busy condition in milliseconds.
+ */
+#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_I2C_BUSY_TIMEOUT 50
+#endif
+
+/**
+ * @brief I2C1 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C2 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C3 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_IRQ_PRIORITY 10
+#endif
+
+/**
+* @brief I2C1 DMA priority (0..3|lowest..highest).
+* @note The priority level is used for both the TX and RX DMA streams but
+* because of the streams ordering the RX stream has always priority
+* over the TX stream.
+*/
+#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_DMA_PRIORITY 1
+#endif
+
+/**
+* @brief I2C2 DMA priority (0..3|lowest..highest).
+* @note The priority level is used for both the TX and RX DMA streams but
+* because of the streams ordering the RX stream has always priority
+* over the TX stream.
+*/
+#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_DMA_PRIORITY 1
+#endif
+
+/**
+* @brief I2C3 DMA priority (0..3|lowest..highest).
+* @note The priority level is used for both the TX and RX DMA streams but
+* because of the streams ordering the RX stream has always priority
+* over the TX stream.
+*/
+#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C 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_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+#endif
+
+#if STM32_ADVANCED_DMA || defined(__DOXYGEN__)
+
+/**
+ * @brief DMA stream used for I2C1 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C1_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
+#endif
+
+/**
+ * @brief DMA stream used for I2C1 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C1_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#endif
+
+/**
+ * @brief DMA stream used for I2C2 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C2_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
+#endif
+
+/**
+ * @brief DMA stream used for I2C2 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C2_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#endif
+
+/**
+ * @brief DMA stream used for I2C3 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C3_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
+#endif
+
+/**
+ * @brief DMA stream used for I2C3 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C3_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+#endif
+
+#else /* !STM32_ADVANCED_DMA */
+
+/* Fixed streams for platforms using the old DMA peripheral, the values are
+ valid for both STM32F1xx and STM32L1xx.*/
+#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
+#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+
+#endif /* !STM32_ADVANCED_DMA*/
+
+/* Flag for the whole STM32F1XX family. */
+#if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \
+ defined(STM32F10X_HD_VL) || defined(STM32F10X_LD) || \
+ defined(STM32F10X_MD) || defined(STM32F10X_HD) || \
+ defined(STM32F10X_XL) || defined(STM32F10X_CL)
+#define STM32F1XX_I2C
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/** @brief error checks */
+#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1
+#error "I2C1 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2
+#error "I2C2 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3
+#error "I2C3 not present in the selected device"
+#endif
+
+#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && \
+ !STM32_I2C_USE_I2C3
+#error "I2C driver activated but no I2C peripheral assigned"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C1"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C2"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C3"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C1"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C2"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C3"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_I2C_USE_I2C1 && (!defined(STM32_I2C_I2C1_RX_DMA_STREAM) || \
+ !defined(STM32_I2C_I2C1_TX_DMA_STREAM))
+#error "I2C1 DMA streams not defined"
+#endif
+
+#if STM32_I2C_USE_I2C2 && (!defined(STM32_I2C_I2C2_RX_DMA_STREAM) || \
+ !defined(STM32_I2C_I2C2_TX_DMA_STREAM))
+#error "I2C2 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \
+ STM32_I2C1_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C1 RX"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \
+ STM32_I2C1_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C1 TX"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \
+ STM32_I2C2_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C2 RX"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \
+ STM32_I2C2_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C2 TX"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \
+ STM32_I2C3_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C3 RX"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \
+ STM32_I2C3_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C3 TX"
+#endif
+#endif /* STM32_ADVANCED_DMA */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/* Check clock range. */
+#if defined(STM32F4XX)
+#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 42)
+#error "I2C peripheral clock frequency out of range."
+#endif
+
+#elif defined(STM32L1XX)
+#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 32)
+#error "I2C peripheral clock frequency out of range."
+#endif
+
+#elif defined(STM32F2XX)
+#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 30)
+#error "I2C peripheral clock frequency out of range."
+#endif
+
+#elif defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \
+ defined(STM32F10X_HD_VL)
+#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 24)
+#error "I2C peripheral clock frequency out of range."
+#endif
+
+#elif defined(STM32F10X_LD) || defined(STM32F10X_MD) || \
+ defined(STM32F10X_HD) || defined(STM32F10X_XL) || \
+ defined(STM32F10X_CL)
+#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 36)
+#error "I2C peripheral clock frequency out of range."
+#endif
+#else
+#error "unspecified, unsupported or invalid STM32 platform"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type representing an I2C address.
+ */
+typedef uint16_t i2caddr_t;
+
+/**
+ * @brief Type of I2C driver condition flags.
+ */
+typedef uint32_t i2cflags_t;
+
+/**
+ * @brief Supported modes for the I2C bus.
+ */
+typedef enum {
+ OPMODE_I2C = 1,
+ OPMODE_SMBUS_DEVICE = 2,
+ OPMODE_SMBUS_HOST = 3,
+} i2copmode_t;
+
+/**
+ * @brief Supported duty cycle modes for the I2C bus.
+ */
+typedef enum {
+ STD_DUTY_CYCLE = 1,
+ FAST_DUTY_CYCLE_2 = 2,
+ FAST_DUTY_CYCLE_16_9 = 3,
+} i2cdutycycle_t;
+
+/**
+ * @brief Type of I2C driver configuration structure.
+ */
+typedef struct {
+ /* End of the mandatory fields.*/
+ i2copmode_t op_mode; /**< @brief Specifies the I2C mode. */
+ uint32_t clock_speed; /**< @brief Specifies the clock frequency.
+ @note Must be set to a value lower
+ than 400kHz. */
+ i2cdutycycle_t duty_cycle; /**< @brief Specifies the I2C fast mode
+ duty cycle. */
+} I2CConfig;
+
+/**
+ * @brief Type of a structure representing an I2C driver.
+ */
+typedef struct I2CDriver I2CDriver;
+
+/**
+ * @brief Structure representing an I2C driver.
+ */
+struct I2CDriver {
+ /**
+ * @brief Driver state.
+ */
+ i2cstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const I2CConfig *config;
+ /**
+ * @brief Error flags.
+ */
+ i2cflags_t errors;
+#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the bus.
+ */
+ mutex_t mutex;
+#endif /* I2C_USE_MUTUAL_EXCLUSION */
+#if defined(I2C_DRIVER_EXT_FIELDS)
+ I2C_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Thread waiting for I/O completion.
+ */
+ thread_reference_t thread;
+ /**
+ * @brief Current slave address without R/W bit.
+ */
+ i2caddr_t addr;
+ /**
+ * @brief RX DMA mode bit mask.
+ */
+ uint32_t rxdmamode;
+ /**
+ * @brief TX DMA mode bit mask.
+ */
+ uint32_t txdmamode;
+ /**
+ * @brief Receive DMA channel.
+ */
+ const stm32_dma_stream_t *dmarx;
+ /**
+ * @brief Transmit DMA channel.
+ */
+ const stm32_dma_stream_t *dmatx;
+ /**
+ * @brief Pointer to the I2Cx registers block.
+ */
+ I2C_TypeDef *i2c;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Get errors from I2C driver.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+#if STM32_I2C_USE_I2C1
+extern I2CDriver I2CD1;
+#endif
+
+#if STM32_I2C_USE_I2C2
+extern I2CDriver I2CD2;
+#endif
+
+#if STM32_I2C_USE_I2C3
+extern I2CDriver I2CD3;
+#endif
+#endif /* !defined(__DOXYGEN__) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void i2c_lld_init(void);
+ void i2c_lld_start(I2CDriver *i2cp);
+ void i2c_lld_stop(I2CDriver *i2cp);
+ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout);
+ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_I2C */
+
+#endif /* HAL_I2C_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk new file mode 100644 index 0000000..69b63ce --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes)
+ # Fallback SW driver.
+ ifeq ($(USE_SMART_BUILD),yes)
+ ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+ PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+ endif
+ else
+ PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+ endif
+ PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C
+else
+ # Default HW driver.
+ ifeq ($(USE_SMART_BUILD),yes)
+ ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c
+ endif
+ else
+ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c
+ endif
+ PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2
+endif
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c new file mode 100644 index 0000000..06c2858 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c @@ -0,0 +1,1169 @@ +/*
+ 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 I2Cv2/hal_i2c_lld.c
+ * @brief STM32 I2C subsystem low level driver source.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#if STM32_I2C_USE_DMA == TRUE
+#define DMAMODE_COMMON \
+ (STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | \
+ STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | \
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE)
+
+#define I2C1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \
+ STM32_I2C1_RX_DMA_CHN)
+
+#define I2C1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \
+ STM32_I2C1_TX_DMA_CHN)
+
+#define I2C2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \
+ STM32_I2C2_RX_DMA_CHN)
+
+#define I2C2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \
+ STM32_I2C2_TX_DMA_CHN)
+
+#define I2C3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \
+ STM32_I2C3_RX_DMA_CHN)
+
+#define I2C3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \
+ STM32_I2C3_TX_DMA_CHN)
+
+#define I2C4_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C4_RX_DMA_STREAM, \
+ STM32_I2C4_RX_DMA_CHN)
+
+#define I2C4_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C4_TX_DMA_STREAM, \
+ STM32_I2C4_TX_DMA_CHN)
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if STM32_I2C_USE_DMA == TRUE
+#define i2c_lld_get_rxbytes(i2cp) dmaStreamGetTransactionSize((i2cp)->dmarx)
+#define i2c_lld_get_txbytes(i2cp) dmaStreamGetTransactionSize((i2cp)->dmatx)
+#else
+#define i2c_lld_get_rxbytes(i2cp) (i2cp)->rxbytes
+#define i2c_lld_get_txbytes(i2cp) (i2cp)->txbytes
+#endif
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define I2C_ERROR_MASK \
+ ((uint32_t)(I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR | I2C_ISR_PECERR | \
+ I2C_ISR_TIMEOUT | I2C_ISR_ALERT))
+
+#define I2C_INT_MASK \
+ ((uint32_t)(I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF | I2C_ISR_NACKF | \
+ I2C_ISR_ADDR | I2C_ISR_RXNE | I2C_ISR_TXIS))
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief I2C1 driver identifier.*/
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+I2CDriver I2CD1;
+#endif
+
+/** @brief I2C2 driver identifier.*/
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+I2CDriver I2CD2;
+#endif
+
+/** @brief I2C3 driver identifier.*/
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+I2CDriver I2CD3;
+#endif
+
+/** @brief I2C4 driver identifier.*/
+#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__)
+I2CDriver I2CD4;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Slave address setup.
+ * @note The RW bit is set to zero internally.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ *
+ * @notapi
+ */
+static void i2c_lld_set_address(I2CDriver *i2cp, i2caddr_t addr) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Address alignment depends on the addressing mode selected.*/
+ if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0U)
+ dp->CR2 = (uint32_t)addr << 1U;
+ else
+ dp->CR2 = (uint32_t)addr;
+}
+
+/**
+ * @brief I2C RX transfer setup.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_setup_rx_transfer(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ uint32_t reload;
+ size_t n;
+
+ /* The unit can transfer 255 bytes maximum in a single operation.*/
+ n = i2c_lld_get_rxbytes(i2cp);
+ if (n > 255U) {
+ n = 255U;
+ reload = I2C_CR2_RELOAD;
+ }
+ else {
+ reload = 0U;
+ }
+
+ /* Configures the CR2 registers with both the calculated and static
+ settings.*/
+ dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 |
+ I2C_CR2_RD_WRN | (n << 16U) | reload;
+}
+
+/**
+ * @brief I2C TX transfer setup.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_setup_tx_transfer(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ uint32_t reload;
+ size_t n;
+
+ /* The unit can transfer 255 bytes maximum in a single operation.*/
+ n = i2c_lld_get_txbytes(i2cp);
+ if (n > 255U) {
+ n = 255U;
+ reload = I2C_CR2_RELOAD;
+ }
+ else {
+ reload = 0U;
+ }
+
+ /* Configures the CR2 registers with both the calculated and static
+ settings.*/
+ dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 |
+ (n << 16U) | reload;
+}
+
+/**
+ * @brief Aborts an I2C transaction.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_abort_operation(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ if (dp->CR1 & I2C_CR1_PE) {
+ /* Stops the I2C peripheral.*/
+ dp->CR1 &= ~I2C_CR1_PE;
+ while (dp->CR1 & I2C_CR1_PE)
+ dp->CR1 &= ~I2C_CR1_PE;
+ dp->CR1 |= I2C_CR1_PE;
+ }
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Stops the associated DMA streams.*/
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+#else
+ dp->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE);
+#endif
+}
+
+/**
+ * @brief I2C shared ISR code.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] isr content of the ISR register to be decoded
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Special case of a received NACK, the transfer is aborted.*/
+ if ((isr & I2C_ISR_NACKF) != 0U) {
+#if STM32_I2C_USE_DMA == TRUE
+ /* Stops the associated DMA streams.*/
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+#endif
+
+ /* Error flag.*/
+ i2cp->errors |= I2C_ACK_FAILURE;
+
+ /* Transaction finished sending the STOP.*/
+ dp->CR2 |= I2C_CR2_STOP;
+
+ /* Make sure no more interrupts.*/
+ dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE);
+
+ /* Errors are signaled to the upper layer.*/
+ _i2c_wakeup_error_isr(i2cp);
+
+ return;
+ }
+
+#if STM32_I2C_USE_DMA == FALSE
+ /* Handling of data transfer if the DMA mode is disabled.*/
+ {
+ uint32_t cr1 = dp->CR1;
+
+ if (i2cp->state == I2C_ACTIVE_TX) {
+ /* Transmission phase.*/
+ if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) {
+ dp->TXDR = (uint32_t)*i2cp->txptr;
+ i2cp->txptr++;
+ i2cp->txbytes--;
+ if (i2cp->txbytes == 0U) {
+ dp->CR1 &= ~I2C_CR1_TXIE;
+ }
+ }
+ }
+ else {
+ /* Receive phase.*/
+ if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) {
+ *i2cp->rxptr = (uint8_t)dp->RXDR;
+ i2cp->rxptr++;
+ i2cp->rxbytes--;
+ if (i2cp->rxbytes == 0U) {
+ dp->CR1 &= ~I2C_CR1_RXIE;
+ }
+ }
+ }
+ }
+#endif
+
+ /* Partial transfer handling, restarting the transfer and returning.*/
+ if ((isr & I2C_ISR_TCR) != 0U) {
+ if (i2cp->state == I2C_ACTIVE_TX) {
+ i2c_lld_setup_tx_transfer(i2cp);
+ }
+ else {
+ i2c_lld_setup_rx_transfer(i2cp);
+ }
+ return;
+ }
+
+ /* The following condition is true if a transfer phase has been completed.*/
+ if ((isr & I2C_ISR_TC) != 0U) {
+ if (i2cp->state == I2C_ACTIVE_TX) {
+ /* End of the transmit phase.*/
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Disabling TX DMA channel.*/
+ dmaStreamDisable(i2cp->dmatx);
+#endif
+
+ /* Starting receive phase if necessary.*/
+ if (i2c_lld_get_rxbytes(i2cp) > 0U) {
+ /* Setting up the peripheral.*/
+ i2c_lld_setup_rx_transfer(i2cp);
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Enabling RX DMA.*/
+ dmaStreamEnable(i2cp->dmarx);
+#else
+ /* RX interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_RXIE;
+#endif
+
+ /* Starts the read operation.*/
+ dp->CR2 |= I2C_CR2_START;
+
+ /* State change.*/
+ i2cp->state = I2C_ACTIVE_RX;
+
+ /* Note, returning because the transaction is not over yet.*/
+ return;
+ }
+ }
+ else {
+ /* End of the receive phase.*/
+#if STM32_I2C_USE_DMA == TRUE
+ /* Disabling RX DMA channel.*/
+ dmaStreamDisable(i2cp->dmarx);
+#endif
+ }
+
+ /* Transaction finished sending the STOP.*/
+ dp->CR2 |= I2C_CR2_STOP;
+
+ /* Make sure no more 'Transfer Complete' interrupts.*/
+ dp->CR1 &= ~I2C_CR1_TCIE;
+
+ /* Normal transaction end.*/
+ _i2c_wakeup_isr(i2cp);
+ }
+}
+
+/**
+ * @brief I2C error handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] isr content of the ISR register to be decoded
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) {
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Clears DMA interrupt flags just to be safe.*/
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+#else
+ /* Disabling RX and TX interrupts.*/
+ i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE);
+#endif
+
+ if (isr & I2C_ISR_BERR)
+ i2cp->errors |= I2C_BUS_ERROR;
+
+ if (isr & I2C_ISR_ARLO)
+ i2cp->errors |= I2C_ARBITRATION_LOST;
+
+ if (isr & I2C_ISR_OVR)
+ i2cp->errors |= I2C_OVERRUN;
+
+ if (isr & I2C_ISR_TIMEOUT)
+ i2cp->errors |= I2C_TIMEOUT;
+
+ /* If some error has been identified then sends wakes the waiting thread.*/
+ if (i2cp->errors != I2C_NO_ERROR)
+ _i2c_wakeup_error_isr(i2cp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+#if defined(STM32_I2C1_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C1 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C1_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD1.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD1.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD1, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C1_EVENT_HANDLER) && defined(STM32_I2C1_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
+ uint32_t isr = I2CD1.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD1.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) {
+ uint32_t isr = I2CD1.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD1.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C1 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+#if defined(STM32_I2C2_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C2 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C2_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD2.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD2.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD2, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD2, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C2_EVENT_HANDLER) && defined(STM32_I2C2_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) {
+ uint32_t isr = I2CD2.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD2.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD2, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) {
+ uint32_t isr = I2CD2.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD2.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD2, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C2 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+#if defined(STM32_I2C3_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C3 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C3_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD3.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD3.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD3, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C3_EVENT_HANDLER) && defined(STM32_I2C3_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) {
+ uint32_t isr = I2CD3.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD3.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) {
+ uint32_t isr = I2CD3.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD3.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C3 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C3 */
+
+#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__)
+#if defined(STM32_I2C4_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C4 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C4_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD4.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD4.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD4, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C4_EVENT_HANDLER) && defined(STM32_I2C4_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C4_EVENT_HANDLER) {
+ uint32_t isr = I2CD4.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD4.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C4_ERROR_HANDLER) {
+ uint32_t isr = I2CD4.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD4.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C4 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C4 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level I2C driver initialization.
+ *
+ * @notapi
+ */
+void i2c_lld_init(void) {
+
+#if STM32_I2C_USE_I2C1
+ i2cObjectInit(&I2CD1);
+ I2CD1.thread = NULL;
+ I2CD1.i2c = I2C1;
+#if STM32_I2C_USE_DMA == TRUE
+ I2CD1.dmarx = NULL;
+ I2CD1.dmatx = NULL;
+#endif
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2
+ i2cObjectInit(&I2CD2);
+ I2CD2.thread = NULL;
+ I2CD2.i2c = I2C2;
+#if STM32_I2C_USE_DMA == TRUE
+ I2CD2.dmarx = NULL;
+ I2CD2.dmatx = NULL;
+#endif
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ i2cObjectInit(&I2CD3);
+ I2CD3.thread = NULL;
+ I2CD3.i2c = I2C3;
+#if STM32_I2C_USE_DMA == TRUE
+ I2CD3.dmarx = NULL;
+ I2CD3.dmatx = NULL;
+#endif
+#endif /* STM32_I2C_USE_I2C3 */
+
+#if STM32_I2C_USE_I2C4
+ i2cObjectInit(&I2CD4);
+ I2CD4.thread = NULL;
+ I2CD4.i2c = I2C4;
+#if STM32_I2C_USE_DMA == TRUE
+ I2CD4.dmarx = NULL;
+ I2CD4.dmatx = NULL;
+#endif
+#endif /* STM32_I2C_USE_I2C4 */
+}
+
+/**
+ * @brief Configures and activates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_start(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Make sure I2C peripheral is disabled */
+ dp->CR1 &= ~I2C_CR1_PE;
+
+ /* If in stopped state then enables the I2C and DMA clocks.*/
+ if (i2cp->state == I2C_STOP) {
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Common DMA modes.*/
+ i2cp->txdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_M2P;
+ i2cp->rxdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_P2M;
+#endif
+
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+
+ rccResetI2C1();
+ rccEnableI2C1(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C1_TX_DMA_STREAM,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C1_RX);
+ dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C1_TX);
+#endif
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C1_GLOBAL_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY);
+#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C1_EVENT_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C1_ERROR_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY);
+#else
+#error "I2C1 interrupt numbers not defined"
+#endif
+ }
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+
+ rccResetI2C2();
+ rccEnableI2C2(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C2_TX_DMA_STREAM,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C2_RX);
+ dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C2_TX);
+#endif
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C2_GLOBAL_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY);
+#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C2_EVENT_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C2_ERROR_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY);
+#else
+#error "I2C2 interrupt numbers not defined"
+#endif
+ }
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+
+ rccResetI2C3();
+ rccEnableI2C3(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C3_TX_DMA_STREAM,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C3_RX);
+ dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C3_TX);
+#endif
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C3_GLOBAL_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY);
+#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C3_EVENT_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C3_ERROR_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY);
+#else
+#error "I2C3 interrupt numbers not defined"
+#endif
+ }
+#endif /* STM32_I2C_USE_I2C3 */
+
+#if STM32_I2C_USE_I2C4
+ if (&I2CD4 == i2cp) {
+
+ rccResetI2C4();
+ rccEnableI2C4(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C4_RX_DMA_STREAM,
+ STM32_I2C_I2C4_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmarx != NULL, "unable to allocate stream");
+ i2cp->dmatx = dmaStreamAllocI(STM32_I2C_I2C4_TX_DMA_STREAM,
+ STM32_I2C_I2C4_IRQ_PRIORITY,
+ NULL,
+ (void *)i2cp);
+ osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C4_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C4_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(i2cp->dmarx, STM32_DMAMUX1_I2C4_RX);
+ dmaSetRequestSource(i2cp->dmatx, STM32_DMAMUX1_I2C4_TX);
+#endif
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C4_GLOBAL_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY);
+#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C4_EVENT_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C4_ERROR_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY);
+#else
+#error "I2C4 interrupt numbers not defined"
+#endif
+ }
+#endif /* STM32_I2C_USE_I2C4 */
+ }
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* I2C registers pointed by the DMA.*/
+ dmaStreamSetPeripheral(i2cp->dmarx, &dp->RXDR);
+ dmaStreamSetPeripheral(i2cp->dmatx, &dp->TXDR);
+#endif
+
+ /* Reset i2c peripheral, the TCIE bit will be handled separately.*/
+ dp->CR1 = i2cp->config->cr1 |
+#if STM32_I2C_USE_DMA == TRUE
+ I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN | /* Enable only if using DMA */
+#endif
+ I2C_CR1_ERRIE | I2C_CR1_NACKIE;
+
+ /* Setup I2C parameters.*/
+ dp->TIMINGR = i2cp->config->timingr;
+
+ /* Ready to go.*/
+ dp->CR1 |= I2C_CR1_PE;
+}
+
+/**
+ * @brief Deactivates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_stop(I2CDriver *i2cp) {
+
+ /* If not in stopped state then disables the I2C clock.*/
+ if (i2cp->state != I2C_STOP) {
+
+ /* I2C disable.*/
+ i2c_lld_abort_operation(i2cp);
+#if STM32_I2C_USE_DMA == TRUE
+ dmaStreamFreeI(i2cp->dmatx);
+ dmaStreamFreeI(i2cp->dmarx);
+ i2cp->dmatx = NULL;
+ i2cp->dmarx = NULL;
+#endif
+
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicDisableVector(STM32_I2C1_GLOBAL_NUMBER);
+#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER)
+ nvicDisableVector(STM32_I2C1_EVENT_NUMBER);
+ nvicDisableVector(STM32_I2C1_ERROR_NUMBER);
+#else
+#error "I2C1 interrupt numbers not defined"
+#endif
+
+ rccDisableI2C1();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicDisableVector(STM32_I2C2_GLOBAL_NUMBER);
+#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER)
+ nvicDisableVector(STM32_I2C2_EVENT_NUMBER);
+ nvicDisableVector(STM32_I2C2_ERROR_NUMBER);
+#else
+#error "I2C2 interrupt numbers not defined"
+#endif
+
+ rccDisableI2C2();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicDisableVector(STM32_I2C3_GLOBAL_NUMBER);
+#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER)
+ nvicDisableVector(STM32_I2C3_EVENT_NUMBER);
+ nvicDisableVector(STM32_I2C3_ERROR_NUMBER);
+#else
+#error "I2C3 interrupt numbers not defined"
+#endif
+
+ rccDisableI2C3();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C4
+ if (&I2CD4 == i2cp) {
+#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicDisableVector(STM32_I2C4_GLOBAL_NUMBER);
+#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER)
+ nvicDisableVector(STM32_I2C4_EVENT_NUMBER);
+ nvicDisableVector(STM32_I2C4_ERROR_NUMBER);
+#else
+#error "I2C4 interrupt numbers not defined"
+#endif
+
+ rccDisableI2C4();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Receives data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout) {
+ msg_t msg;
+ I2C_TypeDef *dp = i2cp->i2c;
+ systime_t start, end;
+
+ /* Resetting error flags for this transfer.*/
+ i2cp->errors = I2C_NO_ERROR;
+
+ /* Releases the lock from high level driver.*/
+ osalSysUnlock();
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* RX DMA setup.*/
+ dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+ dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
+#else
+ i2cp->rxptr = rxbuf;
+ i2cp->rxbytes = rxbytes;
+#endif
+
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT));
+
+ /* Waits until BUSY flag is reset or, alternatively, for a timeout
+ condition.*/
+ while (true) {
+ osalSysLock();
+
+ /* If the bus is not busy then the operation can continue, note, the
+ loop is exited in the locked state.*/
+ if ((dp->ISR & I2C_ISR_BUSY) == 0)
+ break;
+
+ /* If the system time went outside the allowed window then a timeout
+ condition is returned.*/
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return MSG_TIMEOUT;
+ }
+
+ osalSysUnlock();
+ }
+
+ /* Setting up the slave address.*/
+ i2c_lld_set_address(i2cp, addr);
+
+ /* Setting up the peripheral.*/
+ i2c_lld_setup_rx_transfer(i2cp);
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Enabling RX DMA.*/
+ dmaStreamEnable(i2cp->dmarx);
+
+ /* Transfer complete interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE;
+#else
+
+ /* Transfer complete and RX interrupts enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE;
+#endif
+
+ /* Starts the operation.*/
+ dp->CR2 |= I2C_CR2_START;
+
+ /* Waits for the operation completion or a timeout.*/
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+
+ /* In case of a software timeout a STOP is sent as an extreme attempt
+ to release the bus and DMA is forcibly disabled.*/
+ if (msg == MSG_TIMEOUT) {
+ dp->CR2 |= I2C_CR2_STOP;
+#if STM32_I2C_USE_DMA == TRUE
+ dmaStreamDisable(i2cp->dmarx);
+#endif
+ }
+
+ return msg;
+}
+
+/**
+ * @brief Transmits data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout) {
+ msg_t msg;
+ I2C_TypeDef *dp = i2cp->i2c;
+ systime_t start, end;
+
+ /* Resetting error flags for this transfer.*/
+ i2cp->errors = I2C_NO_ERROR;
+
+ /* Releases the lock from high level driver.*/
+ osalSysUnlock();
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* TX DMA setup.*/
+ dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
+ dmaStreamSetMemory0(i2cp->dmatx, txbuf);
+ dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
+
+ /* RX DMA setup, note, rxbytes can be zero but we write the value anyway.*/
+ dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+ dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
+#else
+ i2cp->txptr = txbuf;
+ i2cp->txbytes = txbytes;
+ i2cp->rxptr = rxbuf;
+ i2cp->rxbytes = rxbytes;
+#endif
+
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT));
+
+ /* Waits until BUSY flag is reset or, alternatively, for a timeout
+ condition.*/
+ while (true) {
+ osalSysLock();
+
+ /* If the bus is not busy then the operation can continue, note, the
+ loop is exited in the locked state.*/
+ if ((dp->ISR & I2C_ISR_BUSY) == 0)
+ break;
+
+ /* If the system time went outside the allowed window then a timeout
+ condition is returned.*/
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return MSG_TIMEOUT;
+ }
+
+ osalSysUnlock();
+ }
+
+ /* Setting up the slave address.*/
+ i2c_lld_set_address(i2cp, addr);
+
+ /* Preparing the transfer.*/
+ i2c_lld_setup_tx_transfer(i2cp);
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Enabling TX DMA.*/
+ dmaStreamEnable(i2cp->dmatx);
+
+ /* Transfer complete interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE;
+#else
+ /* Transfer complete and TX interrupts enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE;
+#endif
+
+ /* Starts the operation.*/
+ dp->CR2 |= I2C_CR2_START;
+
+ /* Waits for the operation completion or a timeout.*/
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+
+ /* In case of a software timeout a STOP is sent as an extreme attempt
+ to release the bus and DMA is forcibly disabled.*/
+ if (msg == MSG_TIMEOUT) {
+ dp->CR2 |= I2C_CR2_STOP;
+#if STM32_I2C_USE_DMA == TRUE
+ dmaStreamDisable(i2cp->dmarx);
+ dmaStreamDisable(i2cp->dmatx);
+#endif
+ }
+
+ return msg;
+}
+
+#endif /* HAL_USE_I2C */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h new file mode 100644 index 0000000..b1004e7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.h @@ -0,0 +1,509 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file I2Cv2/hal_i2c_lld.h
+ * @brief STM32 I2C subsystem low level driver header.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#ifndef HAL_I2C_LLD_H
+#define HAL_I2C_LLD_H
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name TIMINGR register definitions
+ * @{
+ */
+#define STM32_TIMINGR_PRESC_MASK (15U << 28)
+#define STM32_TIMINGR_PRESC(n) ((n) << 28)
+#define STM32_TIMINGR_SCLDEL_MASK (15U << 20)
+#define STM32_TIMINGR_SCLDEL(n) ((n) << 20)
+#define STM32_TIMINGR_SDADEL_MASK (15U << 16)
+#define STM32_TIMINGR_SDADEL(n) ((n) << 16)
+#define STM32_TIMINGR_SCLH_MASK (255U << 8)
+#define STM32_TIMINGR_SCLH(n) ((n) << 8)
+#define STM32_TIMINGR_SCLL_MASK (255U << 0)
+#define STM32_TIMINGR_SCLL(n) ((n) << 0)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief I2C1 driver enable switch.
+ * @details If set to @p TRUE the support for I2C1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C1 FALSE
+#endif
+
+/**
+ * @brief I2C2 driver enable switch.
+ * @details If set to @p TRUE the support for I2C2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C2 FALSE
+#endif
+
+/**
+ * @brief I2C3 driver enable switch.
+ * @details If set to @p TRUE the support for I2C3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C3 FALSE
+#endif
+
+/**
+ * @brief I2C4 driver enable switch.
+ * @details If set to @p TRUE the support for I2C4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C4) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C4 FALSE
+#endif
+
+/**
+ * @brief I2C timeout on busy condition in milliseconds.
+ */
+#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_I2C_BUSY_TIMEOUT 50
+#endif
+
+/**
+ * @brief I2C1 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C2 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C3 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C4 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C4_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DMA use switch.
+ */
+#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_DMA TRUE
+#endif
+
+/**
+ * @brief I2C1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C4_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C 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_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/** @brief error checks */
+#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1
+#error "I2C1 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2
+#error "I2C2 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3
+#error "I2C3 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C4 && !STM32_HAS_I2C4
+#error "I2C4 not present in the selected device"
+#endif
+
+#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && !STM32_I2C_USE_I2C3 && \
+ !STM32_I2C_USE_I2C4
+#error "I2C driver activated but no I2C peripheral assigned"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C1"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C2"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C3"
+#endif
+
+#if STM32_I2C_USE_I2C4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C4"
+#endif
+
+#if STM32_I2C_USE_DMA == TRUE
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C1"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C2"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C3"
+#endif
+
+#if STM32_I2C_USE_I2C4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C4"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_I2C_USE_I2C1 && (!defined(STM32_I2C_I2C1_RX_DMA_STREAM) || \
+ !defined(STM32_I2C_I2C1_TX_DMA_STREAM))
+#error "I2C1 DMA streams not defined"
+#endif
+
+#if STM32_I2C_USE_I2C2 && (!defined(STM32_I2C_I2C2_RX_DMA_STREAM) || \
+ !defined(STM32_I2C_I2C2_TX_DMA_STREAM))
+#error "I2C2 DMA streams not defined"
+#endif
+
+#if STM32_I2C_USE_I2C3 && (!defined(STM32_I2C_I2C3_RX_DMA_STREAM) || \
+ !defined(STM32_I2C_I2C3_TX_DMA_STREAM))
+#error "I2C3 DMA streams not defined"
+#endif
+
+#if STM32_I2C_USE_I2C4 && (!defined(STM32_I2C_I2C4_RX_DMA_STREAM) || \
+ !defined(STM32_I2C_I2C4_TX_DMA_STREAM))
+#error "I2C4 DMA streams not defined"
+#endif
+
+/* Devices without DMAMUX require an additional check.*/
+#if !STM32_DMA_SUPPORTS_DMAMUX
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \
+ STM32_I2C1_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C1 RX"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \
+ STM32_I2C1_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C1 TX"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \
+ STM32_I2C2_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C2 RX"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \
+ STM32_I2C2_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C2 TX"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \
+ STM32_I2C3_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C3 RX"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \
+ STM32_I2C3_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C3 TX"
+#endif
+
+#if STM32_I2C_USE_I2C4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C4_RX_DMA_STREAM, \
+ STM32_I2C4_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C4 RX"
+#endif
+
+#if STM32_I2C_USE_I2C4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C4_TX_DMA_STREAM, \
+ STM32_I2C4_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C4 TX"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+#endif /* STM32_ADVANCED_DMA */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type representing an I2C address.
+ */
+typedef uint16_t i2caddr_t;
+
+/**
+ * @brief Type of I2C driver condition flags.
+ */
+typedef uint32_t i2cflags_t;
+
+/**
+ * @brief Type of I2C driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief TIMINGR register initialization.
+ * @note Refer to the STM32 reference manual, the values are affected
+ * by the system clock settings in mcuconf.h.
+ */
+ uint32_t timingr;
+ /**
+ * @brief CR1 register initialization.
+ * @note Leave to zero unless you know what you are doing.
+ */
+ uint32_t cr1;
+ /**
+ * @brief CR2 register initialization.
+ * @note Only the ADD10 bit can eventually be specified here.
+ */
+ uint32_t cr2;
+} I2CConfig;
+
+/**
+ * @brief Type of a structure representing an I2C driver.
+ */
+typedef struct I2CDriver I2CDriver;
+
+/**
+ * @brief Structure representing an I2C driver.
+ */
+struct I2CDriver {
+ /**
+ * @brief Driver state.
+ */
+ i2cstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const I2CConfig *config;
+ /**
+ * @brief Error flags.
+ */
+ i2cflags_t errors;
+#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ mutex_t mutex;
+#endif /* I2C_USE_MUTUAL_EXCLUSION */
+#if defined(I2C_DRIVER_EXT_FIELDS)
+ I2C_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Thread waiting for I/O completion.
+ */
+ thread_reference_t thread;
+#if (STM32_I2C_USE_DMA == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief RX DMA mode bit mask.
+ */
+ uint32_t rxdmamode;
+ /**
+ * @brief TX DMA mode bit mask.
+ */
+ uint32_t txdmamode;
+ /**
+ * @brief Receive DMA channel.
+ */
+ const stm32_dma_stream_t *dmarx;
+ /**
+ * @brief Transmit DMA channel.
+ */
+ const stm32_dma_stream_t *dmatx;
+#else /* STM32_I2C_USE_DMA == FALSE */
+ /**
+ * @brief Pointer to the next TX buffer location.
+ */
+ const uint8_t *txptr;
+ /**
+ * @brief Number of bytes in TX phase.
+ */
+ size_t txbytes;
+ /**
+ * @brief Pointer to the next RX buffer location.
+ */
+ uint8_t *rxptr;
+ /**
+ * @brief Number of bytes in RX phase.
+ */
+ size_t rxbytes;
+#endif /* STM32_I2C_USE_DMA == FALSE */
+ /**
+ * @brief Pointer to the I2Cx registers block.
+ */
+ I2C_TypeDef *i2c;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Get errors from I2C driver.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+#if STM32_I2C_USE_I2C1
+extern I2CDriver I2CD1;
+#endif
+
+#if STM32_I2C_USE_I2C2
+extern I2CDriver I2CD2;
+#endif
+
+#if STM32_I2C_USE_I2C3
+extern I2CDriver I2CD3;
+#endif
+
+#if STM32_I2C_USE_I2C4
+extern I2CDriver I2CD4;
+#endif
+
+#endif /* !defined(__DOXYGEN__) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void i2c_lld_init(void);
+ void i2c_lld_start(I2CDriver *i2cp);
+ void i2c_lld_stop(I2CDriver *i2cp);
+ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout);
+ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_I2C */
+
+#endif /* HAL_I2C_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk new file mode 100644 index 0000000..ef55dfd --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes)
+ # Fallback SW driver.
+ ifeq ($(USE_SMART_BUILD),yes)
+ ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+ PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+ endif
+ else
+ PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+ endif
+ PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C
+else
+ # Default HW driver.
+ ifeq ($(USE_SMART_BUILD),yes)
+ ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
+ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c
+ endif
+ else
+ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c
+ endif
+ PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3
+endif
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c new file mode 100644 index 0000000..24b1ace --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.c @@ -0,0 +1,1316 @@ +/*
+ 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 I2Cv3/hal_i2c_lld.c
+ * @brief STM32 I2C subsystem low level driver source.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#if STM32_I2C_USE_DMA == TRUE
+
+#if defined(STM32_I2C_DMA_REQUIRED)
+#define DMAMODE_COMMON \
+ (STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | \
+ STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | \
+ STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE)
+#endif
+
+#if defined(STM32_I2C_BDMA_REQUIRED)
+#define BDMAMODE_COMMON \
+ (STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE | \
+ STM32_BDMA_CR_MINC | \
+ STM32_BDMA_CR_TEIE | STM32_BDMA_CR_TCIE)
+#endif
+
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if 0
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ }
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define I2C_ERROR_MASK \
+ ((uint32_t)(I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR | I2C_ISR_PECERR | \
+ I2C_ISR_TIMEOUT | I2C_ISR_ALERT))
+
+#define I2C_INT_MASK \
+ ((uint32_t)(I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF | I2C_ISR_NACKF | \
+ I2C_ISR_ADDR | I2C_ISR_RXNE | I2C_ISR_TXIS))
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief I2C1 driver identifier.*/
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+I2CDriver I2CD1;
+#endif
+
+/** @brief I2C2 driver identifier.*/
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+I2CDriver I2CD2;
+#endif
+
+/** @brief I2C3 driver identifier.*/
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+I2CDriver I2CD3;
+#endif
+
+/** @brief I2C4 driver identifier.*/
+#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__)
+I2CDriver I2CD4;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if STM32_I2C_USE_DMA == TRUE
+static inline void i2c_lld_start_rx_dma(I2CDriver *i2cp) {
+
+#if STM32_I2C4_USE_BDMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamEnable(i2cp->rx.bdma);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#endif /* STM32_I2C4_USE_BDMA == TRUE */
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamEnable(i2cp->rx.dma);
+ }
+#endif
+}
+
+static inline void i2c_lld_start_tx_dma(I2CDriver *i2cp) {
+
+#if STM32_I2C4_USE_BDMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamEnable(i2cp->tx.bdma);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#endif /* STM32_I2C4_USE_BDMA == TRUE */
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamEnable(i2cp->tx.dma);
+ }
+#endif
+}
+
+static inline void i2c_lld_stop_rx_dma(I2CDriver *i2cp) {
+
+#if STM32_I2C4_USE_BDMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamDisable(i2cp->rx.bdma);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#endif /* STM32_I2C4_USE_BDMA == TRUE */
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamDisable(i2cp->rx.dma);
+ }
+#endif
+}
+
+static inline void i2c_lld_stop_tx_dma(I2CDriver *i2cp) {
+
+#if STM32_I2C4_USE_BDMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamDisable(i2cp->tx.bdma);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#endif /* STM32_I2C4_USE_BDMA == TRUE */
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamDisable(i2cp->tx.dma);
+ }
+#endif
+}
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+/**
+ * @brief Slave address setup.
+ * @note The RW bit is set to zero internally.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ *
+ * @notapi
+ */
+static void i2c_lld_set_address(I2CDriver *i2cp, i2caddr_t addr) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Address alignment depends on the addressing mode selected.*/
+ if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0U)
+ dp->CR2 = (uint32_t)addr << 1U;
+ else
+ dp->CR2 = (uint32_t)addr;
+}
+
+/**
+ * @brief I2C RX transfer setup.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_setup_rx_transfer(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ uint32_t reload;
+ size_t n;
+
+ /* The unit can transfer 255 bytes maximum in a single operation.*/
+ n = i2cp->rxbytes;
+ if (n > 255U) {
+ n = 255U;
+ reload = I2C_CR2_RELOAD;
+ }
+ else {
+ reload = 0U;
+ }
+ i2cp->rxbytes -= n;
+
+ /* Configures the CR2 registers with both the calculated and static
+ settings.*/
+ dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 |
+ I2C_CR2_RD_WRN | (n << 16U) | reload;
+}
+
+/**
+ * @brief I2C TX transfer setup.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_setup_tx_transfer(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+ uint32_t reload;
+ size_t n;
+
+ /* The unit can transfer 255 bytes maximum in a single operation.*/
+ n = i2cp->txbytes;
+ if (n > 255U) {
+ n = 255U;
+ reload = I2C_CR2_RELOAD;
+ }
+ else {
+ reload = 0U;
+ }
+ i2cp->txbytes -= n;
+
+ /* Configures the CR2 registers with both the calculated and static
+ settings.*/
+ dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 |
+ (n << 16U) | reload;
+}
+
+/**
+ * @brief Aborts an I2C transaction.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_lld_abort_operation(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ if (dp->CR1 & I2C_CR1_PE) {
+ /* Stops the I2C peripheral.*/
+ dp->CR1 &= ~I2C_CR1_PE;
+ while (dp->CR1 & I2C_CR1_PE)
+ dp->CR1 &= ~I2C_CR1_PE;
+ dp->CR1 |= I2C_CR1_PE;
+ }
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Stops the associated DMA streams.*/
+ i2c_lld_stop_rx_dma(i2cp);
+ i2c_lld_stop_tx_dma(i2cp);
+#else
+ dp->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE);
+#endif
+}
+
+/**
+ * @brief I2C shared ISR code.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] isr content of the ISR register to be decoded
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Special case of a received NACK, the transfer is aborted.*/
+ if ((isr & I2C_ISR_NACKF) != 0U) {
+#if STM32_I2C_USE_DMA == TRUE
+ /* Stops the associated DMA streams.*/
+ i2c_lld_stop_rx_dma(i2cp);
+ i2c_lld_stop_tx_dma(i2cp);
+#endif
+
+ /* Error flag.*/
+ i2cp->errors |= I2C_ACK_FAILURE;
+
+ /* Transaction finished sending the STOP.*/
+ dp->CR2 |= I2C_CR2_STOP;
+
+ /* Make sure no more interrupts.*/
+ dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE);
+
+ /* Errors are signaled to the upper layer.*/
+ _i2c_wakeup_error_isr(i2cp);
+
+ return;
+ }
+
+#if STM32_I2C_USE_DMA == FALSE
+ /* Handling of data transfer if the DMA mode is disabled.*/
+ {
+ uint32_t cr1 = dp->CR1;
+
+ if (i2cp->state == I2C_ACTIVE_TX) {
+ /* Transmission phase.*/
+ if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) {
+ dp->TXDR = (uint32_t)*i2cp->txptr;
+ i2cp->txptr++;
+ i2cp->txbytes--;
+ if (i2cp->txbytes == 0U) {
+ dp->CR1 &= ~I2C_CR1_TXIE;
+ }
+ }
+ }
+ else {
+ /* Receive phase.*/
+ if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) {
+ *i2cp->rxptr = (uint8_t)dp->RXDR;
+ i2cp->rxptr++;
+ i2cp->rxbytes--;
+ if (i2cp->rxbytes == 0U) {
+ dp->CR1 &= ~I2C_CR1_RXIE;
+ }
+ }
+ }
+ }
+#endif
+
+ /* Partial transfer handling, restarting the transfer and returning.*/
+ if ((isr & I2C_ISR_TCR) != 0U) {
+ if (i2cp->state == I2C_ACTIVE_TX) {
+ i2c_lld_setup_tx_transfer(i2cp);
+ }
+ else {
+ i2c_lld_setup_rx_transfer(i2cp);
+ }
+ return;
+ }
+
+ /* The following condition is true if a transfer phase has been completed.*/
+ if ((isr & I2C_ISR_TC) != 0U) {
+ if (i2cp->state == I2C_ACTIVE_TX) {
+ /* End of the transmit phase.*/
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Disabling TX DMA channel.*/
+ i2c_lld_stop_tx_dma(i2cp);
+#endif
+
+ /* Starting receive phase if necessary.*/
+ if (i2cp->rxbytes > 0U) {
+ /* Setting up the peripheral.*/
+ i2c_lld_setup_rx_transfer(i2cp);
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Enabling RX DMA.*/
+ i2c_lld_start_rx_dma(i2cp);
+#else
+ /* RX interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_RXIE;
+#endif
+
+ /* Starts the read operation.*/
+ dp->CR2 |= I2C_CR2_START;
+
+ /* State change.*/
+ i2cp->state = I2C_ACTIVE_RX;
+
+ /* Note, returning because the transaction is not over yet.*/
+ return;
+ }
+ }
+ else {
+ /* End of the receive phase.*/
+#if STM32_I2C_USE_DMA == TRUE
+ /* Disabling RX DMA channel.*/
+ i2c_lld_stop_rx_dma(i2cp);
+#endif
+ }
+
+ /* Transaction finished sending the STOP.*/
+ dp->CR2 |= I2C_CR2_STOP;
+
+ /* Make sure no more 'Transfer Complete' interrupts.*/
+ dp->CR1 &= ~I2C_CR1_TCIE;
+
+ /* Normal transaction end.*/
+ _i2c_wakeup_isr(i2cp);
+ }
+}
+
+/**
+ * @brief I2C error handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] isr content of the ISR register to be decoded
+ *
+ * @notapi
+ */
+static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) {
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Clears DMA interrupt flags just to be safe.*/
+ i2c_lld_stop_rx_dma(i2cp);
+ i2c_lld_stop_tx_dma(i2cp);
+#else
+ /* Disabling RX and TX interrupts.*/
+ i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE);
+#endif
+
+ if (isr & I2C_ISR_BERR)
+ i2cp->errors |= I2C_BUS_ERROR;
+
+ if (isr & I2C_ISR_ARLO)
+ i2cp->errors |= I2C_ARBITRATION_LOST;
+
+ if (isr & I2C_ISR_OVR)
+ i2cp->errors |= I2C_OVERRUN;
+
+ if (isr & I2C_ISR_TIMEOUT)
+ i2cp->errors |= I2C_TIMEOUT;
+
+ /* If some error has been identified then wake the waiting thread.*/
+ if (i2cp->errors != I2C_NO_ERROR)
+ _i2c_wakeup_error_isr(i2cp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+#if defined(STM32_I2C1_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C1 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C1_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD1.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD1.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD1, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C1_EVENT_HANDLER) && defined(STM32_I2C1_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
+ uint32_t isr = I2CD1.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD1.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) {
+ uint32_t isr = I2CD1.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD1.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD1, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C1 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+#if defined(STM32_I2C2_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C2 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C2_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD2.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD2.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD2, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD2, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C2_EVENT_HANDLER) && defined(STM32_I2C2_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) {
+ uint32_t isr = I2CD2.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD2.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD2, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) {
+ uint32_t isr = I2CD2.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD2.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD2, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C2 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+#if defined(STM32_I2C3_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C3 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C3_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD3.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD3.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD3, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C3_EVENT_HANDLER) && defined(STM32_I2C3_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) {
+ uint32_t isr = I2CD3.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD3.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) {
+ uint32_t isr = I2CD3.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD3.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD3, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C3 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C3 */
+
+#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__)
+#if defined(STM32_I2C4_GLOBAL_HANDLER) || defined(__DOXYGEN__)
+/**
+ * @brief I2C4 event interrupt handler.
+ *
+ * @notapi
+ */
+OSAL_IRQ_HANDLER(STM32_I2C4_GLOBAL_HANDLER) {
+ uint32_t isr = I2CD4.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD4.i2c->ICR = isr;
+
+ if (isr & I2C_ERROR_MASK)
+ i2c_lld_serve_error_interrupt(&I2CD4, isr);
+ else if (isr & I2C_INT_MASK)
+ i2c_lld_serve_interrupt(&I2CD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32_I2C4_EVENT_HANDLER) && defined(STM32_I2C4_ERROR_HANDLER)
+OSAL_IRQ_HANDLER(STM32_I2C4_EVENT_HANDLER) {
+ uint32_t isr = I2CD4.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD4.i2c->ICR = isr & I2C_INT_MASK;
+
+ i2c_lld_serve_interrupt(&I2CD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+OSAL_IRQ_HANDLER(STM32_I2C4_ERROR_HANDLER) {
+ uint32_t isr = I2CD4.i2c->ISR;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Clearing IRQ bits.*/
+ I2CD4.i2c->ICR = isr & I2C_ERROR_MASK;
+
+ i2c_lld_serve_error_interrupt(&I2CD4, isr);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "I2C4 interrupt handlers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C4 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level I2C driver initialization.
+ *
+ * @notapi
+ */
+void i2c_lld_init(void) {
+
+#if STM32_I2C_USE_I2C1
+ i2cObjectInit(&I2CD1);
+ I2CD1.thread = NULL;
+ I2CD1.i2c = I2C1;
+#if STM32_I2C_USE_DMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ I2CD1.is_bdma = false;
+#endif
+ I2CD1.rx.dma = NULL;
+ I2CD1.tx.dma = NULL;
+#endif
+#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C1_GLOBAL_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY);
+#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C1_EVENT_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C1_ERROR_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY);
+#else
+#error "I2C1 interrupt numbers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2
+ i2cObjectInit(&I2CD2);
+ I2CD2.thread = NULL;
+ I2CD2.i2c = I2C2;
+#if STM32_I2C_USE_DMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ I2CD2.is_bdma = false;
+#endif
+ I2CD2.rx.dma = NULL;
+ I2CD2.tx.dma = NULL;
+#endif
+#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C2_GLOBAL_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY);
+#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C2_EVENT_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C2_ERROR_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY);
+#else
+#error "I2C2 interrupt numbers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ i2cObjectInit(&I2CD3);
+ I2CD3.thread = NULL;
+ I2CD3.i2c = I2C3;
+#if STM32_I2C_USE_DMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ I2CD3.is_bdma = false;
+#endif
+ I2CD3.rx.dma = NULL;
+ I2CD3.tx.dma = NULL;
+#endif
+#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C3_GLOBAL_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY);
+#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C3_EVENT_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C3_ERROR_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY);
+#else
+#error "I2C3 interrupt numbers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C3 */
+
+#if STM32_I2C_USE_I2C4
+ i2cObjectInit(&I2CD4);
+ I2CD4.thread = NULL;
+ I2CD4.i2c = I2C4;
+#if STM32_I2C_USE_DMA == TRUE
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+#if STM32_I2C4_USE_BDMA == TRUE
+ I2CD4.is_bdma = true;
+ I2CD4.rx.bdma = NULL;
+ I2CD4.tx.bdma = NULL;
+#else
+ I2CD4.is_bdma = false;
+ I2CD4.rx.dma = NULL;
+ I2CD4.tx.dma = NULL;
+#endif /* STM32_I2C4_USE_BDMA == TRUE */
+#endif /* defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED) */
+#endif /* STM32_I2C_USE_DMA == TRUE */
+#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__)
+ nvicEnableVector(STM32_I2C4_GLOBAL_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY);
+#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER)
+ nvicEnableVector(STM32_I2C4_EVENT_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY);
+ nvicEnableVector(STM32_I2C4_ERROR_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY);
+#else
+#error "I2C4 interrupt numbers not defined"
+#endif
+#endif /* STM32_I2C_USE_I2C4 */
+}
+
+/**
+ * @brief Configures and activates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_start(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->i2c;
+
+ /* Make sure I2C peripheral is disabled */
+ dp->CR1 &= ~I2C_CR1_PE;
+
+ /* If in stopped state then enables the I2C and DMA clocks.*/
+ if (i2cp->state == I2C_STOP) {
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Common DMA modes.*/
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ i2cp->txdmamode = BDMAMODE_COMMON | STM32_BDMA_CR_DIR_M2P;
+ i2cp->rxdmamode = BDMAMODE_COMMON | STM32_BDMA_CR_DIR_P2M;
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ i2cp->txdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_M2P;
+ i2cp->rxdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_P2M;
+ }
+#endif
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+
+ rccResetI2C1();
+ rccEnableI2C1(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream");
+ i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C1_TX_DMA_STREAM,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+ dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C1_RX);
+ dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C1_TX);
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+ }
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+
+ rccResetI2C2();
+ rccEnableI2C2(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream");
+ i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C2_TX_DMA_STREAM,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+ dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C2_RX);
+ dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C2_TX);
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+ }
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+
+ rccResetI2C3();
+ rccEnableI2C3(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+ i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream");
+ i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C3_TX_DMA_STREAM,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+ dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C3_RX);
+ dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C3_TX);
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+ }
+#endif /* STM32_I2C_USE_I2C3 */
+
+#if STM32_I2C_USE_I2C4
+ if (&I2CD4 == i2cp) {
+
+ rccResetI2C4();
+ rccEnableI2C4(true);
+#if STM32_I2C_USE_DMA == TRUE
+ {
+#if STM32_I2C4_USE_BDMA == TRUE
+ i2cp->rx.bdma = bdmaStreamAllocI(STM32_I2C_I2C4_RX_BDMA_STREAM,
+ STM32_I2C_I2C4_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->rx.bdma != NULL, "unable to allocate stream");
+ i2cp->tx.bdma = bdmaStreamAllocI(STM32_I2C_I2C4_TX_BDMA_STREAM,
+ STM32_I2C_I2C4_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->tx.bdma != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_BDMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_BDMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY);
+ bdmaSetRequestSource(i2cp->rx.bdma, STM32_DMAMUX2_I2C4_RX);
+ bdmaSetRequestSource(i2cp->tx.bdma, STM32_DMAMUX2_I2C4_TX);
+#else /* STM32_I2C4_USE_BDMA != TRUE */
+ i2cp->rx.dma = dmaStreamAllocI(STM32_I2C_I2C4_RX_DMA_STREAM,
+ STM32_I2C_I2C4_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->rx.dma != NULL, "unable to allocate stream");
+ i2cp->tx.dma = dmaStreamAllocI(STM32_I2C_I2C4_TX_DMA_STREAM,
+ STM32_I2C_I2C4_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(i2cp->tx.dma != NULL, "unable to allocate stream");
+
+ i2cp->rxdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY);
+ i2cp->txdmamode |= STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY);
+ dmaSetRequestSource(i2cp->rx.dma, STM32_DMAMUX1_I2C4_RX);
+ dmaSetRequestSource(i2cp->tx.dma, STM32_DMAMUX1_I2C4_TX);
+#endif /* STM32_I2C4_USE_BDMA != TRUE */
+ }
+#endif /* STM32_I2C_USE_DMA == TRUE */
+ }
+#endif /* STM32_I2C_USE_I2C4 */
+ }
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* I2C registers pointed by the DMA.*/
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamSetPeripheral(i2cp->rx.bdma, &dp->RXDR);
+ bdmaStreamSetPeripheral(i2cp->tx.bdma, &dp->TXDR);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamSetPeripheral(i2cp->rx.dma, &dp->RXDR);
+ dmaStreamSetPeripheral(i2cp->tx.dma, &dp->TXDR);
+ }
+#endif
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+ /* Reset i2c peripheral, the TCIE bit will be handled separately.*/
+ dp->CR1 = i2cp->config->cr1 |
+#if STM32_I2C_USE_DMA == TRUE
+ I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN | /* Enable only if using DMA */
+#endif
+ I2C_CR1_ERRIE | I2C_CR1_NACKIE;
+
+ /* Setup I2C parameters.*/
+ dp->TIMINGR = i2cp->config->timingr;
+
+ /* Ready to go.*/
+ dp->CR1 |= I2C_CR1_PE;
+}
+
+/**
+ * @brief Deactivates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_stop(I2CDriver *i2cp) {
+
+ /* If not in stopped state then disables the I2C clock.*/
+ if (i2cp->state != I2C_STOP) {
+
+ /* I2C disable.*/
+ i2c_lld_abort_operation(i2cp);
+
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamFreeI(i2cp->rx.bdma);
+ bdmaStreamFreeI(i2cp->tx.bdma);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamFreeI(i2cp->rx.dma);
+ dmaStreamFreeI(i2cp->tx.dma);
+ }
+#endif
+
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ rccDisableI2C1();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+ rccDisableI2C2();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+ rccDisableI2C3();
+ }
+#endif
+
+#if STM32_I2C_USE_I2C4
+ if (&I2CD4 == i2cp) {
+ rccDisableI2C4();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Receives data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout) {
+ msg_t msg;
+ I2C_TypeDef *dp = i2cp->i2c;
+ systime_t start, end;
+
+ /* Resetting error flags for this transfer.*/
+ i2cp->errors = I2C_NO_ERROR;
+
+ /* Releases the lock from high level driver.*/
+ osalSysUnlock();
+
+ /* Sizes of transfer phases.*/
+ i2cp->txbytes = 0U;
+ i2cp->rxbytes = rxbytes;
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* RX DMA setup.*/
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamSetMode(i2cp->rx.bdma, i2cp->rxdmamode);
+ bdmaStreamSetMemory(i2cp->rx.bdma, rxbuf);
+ bdmaStreamSetTransactionSize(i2cp->rx.bdma, rxbytes);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamSetMode(i2cp->rx.dma, i2cp->rxdmamode);
+ dmaStreamSetMemory0(i2cp->rx.dma, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->rx.dma, rxbytes);
+ }
+#endif
+#else
+ i2cp->rxptr = rxbuf;
+#endif
+
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT));
+
+ /* Waits until BUSY flag is reset or, alternatively, for a timeout
+ condition.*/
+ while (true) {
+ osalSysLock();
+
+ /* If the bus is not busy then the operation can continue, note, the
+ loop is exited in the locked state.*/
+ if ((dp->ISR & I2C_ISR_BUSY) == 0)
+ break;
+
+ /* If the system time went outside the allowed window then a timeout
+ condition is returned.*/
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return MSG_TIMEOUT;
+ }
+
+ osalSysUnlock();
+ }
+
+ /* Setting up the slave address.*/
+ i2c_lld_set_address(i2cp, addr);
+
+ /* Setting up the peripheral.*/
+ i2c_lld_setup_rx_transfer(i2cp);
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Enabling RX DMA.*/
+ i2c_lld_start_rx_dma(i2cp);
+
+ /* Transfer complete interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE;
+#else
+
+ /* Transfer complete and RX interrupts enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE;
+#endif
+
+ /* Starts the operation.*/
+ dp->CR2 |= I2C_CR2_START;
+
+ /* Waits for the operation completion or a timeout.*/
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+
+ /* In case of a software timeout a STOP is sent as an extreme attempt
+ to release the bus and DMA is forcibly disabled.*/
+ if (msg == MSG_TIMEOUT) {
+ dp->CR2 |= I2C_CR2_STOP;
+#if STM32_I2C_USE_DMA == TRUE
+ i2c_lld_stop_rx_dma(i2cp);
+#endif
+ }
+
+ return msg;
+}
+
+/**
+ * @brief Transmits data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] addr slave device address
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[out] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval MSG_OK if the function succeeded.
+ * @retval MSG_RESET if one or more I2C errors occurred, the errors can
+ * be retrieved using @p i2cGetErrors().
+ * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @notapi
+ */
+msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout) {
+ msg_t msg;
+ I2C_TypeDef *dp = i2cp->i2c;
+ systime_t start, end;
+
+ /* Resetting error flags for this transfer.*/
+ i2cp->errors = I2C_NO_ERROR;
+
+ /* Releases the lock from high level driver.*/
+ osalSysUnlock();
+
+ /* Sizes of transfer phases.*/
+ i2cp->txbytes = txbytes;
+ i2cp->rxbytes = rxbytes;
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* TX and RX DMA setup.*/
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ if (i2cp->is_bdma)
+#endif
+#if defined(STM32_I2C_BDMA_REQUIRED)
+ {
+ bdmaStreamSetMode(i2cp->tx.bdma, i2cp->txdmamode);
+ bdmaStreamSetMemory(i2cp->tx.bdma, txbuf);
+ bdmaStreamSetTransactionSize(i2cp->tx.bdma, txbytes);
+
+ bdmaStreamSetMode(i2cp->rx.bdma, i2cp->rxdmamode);
+ bdmaStreamSetMemory(i2cp->rx.bdma, rxbuf);
+ bdmaStreamSetTransactionSize(i2cp->rx.bdma, rxbytes);
+ }
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_I2C_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_I2C_DMA_REQUIRED)
+ {
+ dmaStreamSetMode(i2cp->tx.dma, i2cp->txdmamode);
+ dmaStreamSetMemory0(i2cp->tx.dma, txbuf);
+ dmaStreamSetTransactionSize(i2cp->tx.dma, txbytes);
+
+ dmaStreamSetMode(i2cp->rx.dma, i2cp->rxdmamode);
+ dmaStreamSetMemory0(i2cp->rx.dma, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->rx.dma, rxbytes);
+ }
+#endif
+#else
+ i2cp->txptr = txbuf;
+ i2cp->rxptr = rxbuf;
+#endif
+
+ /* Calculating the time window for the timeout on the busy bus condition.*/
+ start = osalOsGetSystemTimeX();
+ end = osalTimeAddX(start, OSAL_MS2I(STM32_I2C_BUSY_TIMEOUT));
+
+ /* Waits until BUSY flag is reset or, alternatively, for a timeout
+ condition.*/
+ while (true) {
+ osalSysLock();
+
+ /* If the bus is not busy then the operation can continue, note, the
+ loop is exited in the locked state.*/
+ if ((dp->ISR & I2C_ISR_BUSY) == 0)
+ break;
+
+ /* If the system time went outside the allowed window then a timeout
+ condition is returned.*/
+ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) {
+ return MSG_TIMEOUT;
+ }
+
+ osalSysUnlock();
+ }
+
+ /* Setting up the slave address.*/
+ i2c_lld_set_address(i2cp, addr);
+
+ /* Preparing the transfer.*/
+ i2c_lld_setup_tx_transfer(i2cp);
+
+#if STM32_I2C_USE_DMA == TRUE
+ /* Enabling TX DMA.*/
+ i2c_lld_start_tx_dma(i2cp);
+
+ /* Transfer complete interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE;
+#else
+ /* Transfer complete and TX interrupts enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE;
+#endif
+
+ /* Starts the operation.*/
+ dp->CR2 |= I2C_CR2_START;
+
+ /* Waits for the operation completion or a timeout.*/
+ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
+
+ /* In case of a software timeout a STOP is sent as an extreme attempt
+ to release the bus and DMA is forcibly disabled.*/
+ if (msg == MSG_TIMEOUT) {
+ dp->CR2 |= I2C_CR2_STOP;
+#if STM32_I2C_USE_DMA == TRUE
+ i2c_lld_stop_rx_dma(i2cp);
+ i2c_lld_stop_tx_dma(i2cp);
+#endif
+ }
+
+ return msg;
+}
+
+#endif /* HAL_USE_I2C */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h new file mode 100644 index 0000000..ee29a4e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/I2Cv3/hal_i2c_lld.h @@ -0,0 +1,603 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file I2Cv3/hal_i2c_lld.h
+ * @brief STM32 I2C subsystem low level driver header.
+ *
+ * @addtogroup I2C
+ * @{
+ */
+
+#ifndef HAL_I2C_LLD_H
+#define HAL_I2C_LLD_H
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name TIMINGR register definitions
+ * @{
+ */
+#define STM32_TIMINGR_PRESC_MASK (15U << 28)
+#define STM32_TIMINGR_PRESC(n) ((n) << 28)
+#define STM32_TIMINGR_SCLDEL_MASK (15U << 20)
+#define STM32_TIMINGR_SCLDEL(n) ((n) << 20)
+#define STM32_TIMINGR_SDADEL_MASK (15U << 16)
+#define STM32_TIMINGR_SDADEL(n) ((n) << 16)
+#define STM32_TIMINGR_SCLH_MASK (255U << 8)
+#define STM32_TIMINGR_SCLH(n) ((n) << 8)
+#define STM32_TIMINGR_SCLL_MASK (255U << 0)
+#define STM32_TIMINGR_SCLL(n) ((n) << 0)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief I2C1 driver enable switch.
+ * @details If set to @p TRUE the support for I2C1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C1 FALSE
+#endif
+
+/**
+ * @brief I2C2 driver enable switch.
+ * @details If set to @p TRUE the support for I2C2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C2 FALSE
+#endif
+
+/**
+ * @brief I2C3 driver enable switch.
+ * @details If set to @p TRUE the support for I2C3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C3 FALSE
+#endif
+
+/**
+ * @brief I2C4 driver enable switch.
+ * @details If set to @p TRUE the support for I2C4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C4) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C4 FALSE
+#endif
+
+/**
+ * @brief I2C timeout on busy condition in milliseconds.
+ */
+#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_I2C_BUSY_TIMEOUT 50
+#endif
+
+/**
+ * @brief I2C1 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C2 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C3 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2C4 interrupt priority level setting.
+ */
+#if !defined(STM32_I2C_I2C4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C4_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief DMA use switch.
+ */
+#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_DMA TRUE
+#endif
+
+/**
+ * @brief I2C1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_I2C_I2C4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C4_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2C 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_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Registry checks.*/
+#if !defined(STM32_HAS_I2C1)
+#error "STM32_HAS_I2C1 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_I2C2)
+#error "STM32_HAS_I2C2 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_I2C3)
+#error "STM32_HAS_I2C3 not defined in registry"
+#endif
+
+#if !defined(STM32_HAS_I2C4)
+#error "STM32_HAS_I2C4 not defined in registry"
+#endif
+
+#if !defined(STM32_I2C4_USE_BDMA)
+#error "STM32_I2C4_USE_BDMA not defined in registry"
+#endif
+
+/** @brief error checks */
+#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1
+#error "I2C1 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2
+#error "I2C2 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3
+#error "I2C3 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C4 && !STM32_HAS_I2C4
+#error "I2C4 not present in the selected device"
+#endif
+
+#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && !STM32_I2C_USE_I2C3 && \
+ !STM32_I2C_USE_I2C4
+#error "I2C driver activated but no I2C peripheral assigned"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C1"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C2"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C3"
+#endif
+
+#if STM32_I2C_USE_I2C4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to I2C4"
+#endif
+
+#if STM32_I2C_USE_DMA == TRUE
+
+#if STM32_I2C_USE_I2C1
+#if !defined(STM32_I2C_I2C1_RX_DMA_STREAM)
+#error "STM32_I2C_I2C1_RX_DMA_STREAM not defined"
+#endif
+
+#if !defined(STM32_I2C_I2C1_TX_DMA_STREAM)
+#error "STM32_I2C_I2C1_TX_DMA_STREAM not defined"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C1 RX"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C1 TX"
+#endif
+
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C1"
+#endif
+#endif
+
+#if STM32_I2C_USE_I2C2
+#if !defined(STM32_I2C_I2C2_RX_DMA_STREAM)
+#error "STM32_I2C_I2C2_RX_DMA_STREAM not defined"
+#endif
+
+#if !defined(STM32_I2C_I2C2_TX_DMA_STREAM)
+#error "STM32_I2C_I2C2_TX_DMA_STREAM not defined"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C2 RX"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C2 TX"
+#endif
+
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C2"
+#endif
+#endif
+
+#if STM32_I2C_USE_I2C3
+#if !defined(STM32_I2C_I2C3_RX_DMA_STREAM)
+#error "STM32_I2C_I2C3_RX_DMA_STREAM not defined"
+#endif
+
+#if !defined(STM32_I2C_I2C3_TX_DMA_STREAM)
+#error "STM32_I2C_I2C3_TX_DMA_STREAM not defined"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C3 RX"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C3 TX"
+#endif
+
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C3"
+#endif
+#endif
+
+#if STM32_I2C_USE_I2C4
+#if STM32_I2C4_USE_BDMA
+
+#if !defined(STM32_I2C_I2C4_RX_BDMA_STREAM)
+#error "STM32_I2C_I2C4_RX_BDMA_STREAM not defined"
+#endif
+
+#if !defined(STM32_I2C_I2C4_TX_BDMA_STREAM)
+#error "STM32_I2C_I2C4_TX_BDMA_STREAM not defined"
+#endif
+
+#if !STM32_BDMA_IS_VALID_STREAM(STM32_I2C_I2C4_RX_BDMA_STREAM)
+#error "Invalid BDMA stream assigned to I2C4 RX"
+#endif
+
+#if !STM32_BDMA_IS_VALID_STREAM(STM32_I2C_I2C4_TX_BDMA_STREAM)
+#error "Invalid BDMA stream assigned to I2C4 TX"
+#endif
+
+#if !STM32_BDMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C4"
+#endif
+
+#else /* !STM32_I2C4_USE_BDMA */
+
+#if !defined(STM32_I2C_I2C4_RX_DMA_STREAM)
+#error "STM32_I2C_I2C4_RX_DMA_STREAM not defined"
+#endif
+
+#if !defined(STM32_I2C_I2C4_TX_DMA_STREAM)
+#error "STM32_I2C_I2C4_TX_DMA_STREAM not defined"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C4_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C4 RX"
+#endif
+
+#if !STM32_DMA_IS_VALID_STREAM(STM32_I2C_I2C4_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to I2C4 TX"
+#endif
+
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to I2C4"
+#endif
+
+#endif /* !STM32_I2C4_USE_BDMA */
+#endif /* STM32_I2C_USE_I2C4 */
+
+#if STM32_I2C4_USE_BDMA == TRUE
+
+#if STM32_I2C_USE_I2C1 || STM32_I2C_USE_I2C2 || STM32_I2C_USE_I2C3
+#define STM32_I2C_DMA_REQUIRED
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+#endif
+
+#if STM32_I2C_USE_I2C4
+#define STM32_I2C_BDMA_REQUIRED
+#if !defined(STM32_BDMA_REQUIRED)
+#define STM32_BDMA_REQUIRED
+#endif
+#endif
+#else /* STM32_I2C4_USE_BDMA != TRUE */
+
+#if STM32_I2C_USE_I2C1 || STM32_I2C_USE_I2C2 || STM32_I2C_USE_I2C3 || STM32_I2C_USE_I2C4
+#define STM32_I2C_DMA_REQUIRED
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+#endif
+
+#endif /* STM32_I2C4_USE_BDMA != TRUE */
+
+#endif /* STM32_I2C_USE_DMA == TRUE */
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type representing an I2C address.
+ */
+typedef uint16_t i2caddr_t;
+
+/**
+ * @brief Type of I2C driver condition flags.
+ */
+typedef uint32_t i2cflags_t;
+
+/**
+ * @brief Type of I2C driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief TIMINGR register initialization.
+ * @note Refer to the STM32 reference manual, the values are affected
+ * by the system clock settings in mcuconf.h.
+ */
+ uint32_t timingr;
+ /**
+ * @brief CR1 register initialization.
+ * @note Leave to zero unless you know what you are doing.
+ */
+ uint32_t cr1;
+ /**
+ * @brief CR2 register initialization.
+ * @note Only the ADD10 bit can eventually be specified here.
+ */
+ uint32_t cr2;
+} I2CConfig;
+
+/**
+ * @brief Type of a structure representing an I2C driver.
+ */
+typedef struct I2CDriver I2CDriver;
+
+/**
+ * @brief Structure representing an I2C driver.
+ */
+struct I2CDriver {
+ /**
+ * @brief Driver state.
+ */
+ i2cstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const I2CConfig *config;
+ /**
+ * @brief Error flags.
+ */
+ i2cflags_t errors;
+#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ mutex_t mutex;
+#endif /* I2C_USE_MUTUAL_EXCLUSION */
+#if defined(I2C_DRIVER_EXT_FIELDS)
+ I2C_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Thread waiting for I/O completion.
+ */
+ thread_reference_t thread;
+ /**
+ * @brief Number of bytes in TX phase.
+ */
+ size_t txbytes;
+ /**
+ * @brief Number of bytes in RX phase.
+ */
+ size_t rxbytes;
+#if (STM32_I2C_USE_DMA == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief RX DMA mode bit mask.
+ */
+ uint32_t rxdmamode;
+ /**
+ * @brief TX DMA mode bit mask.
+ */
+ uint32_t txdmamode;
+#if defined(STM32_I2C_DMA_REQUIRED) && defined(STM32_BDMA_REQUIRED)
+ /**
+ * @brief DMA type for this instance.
+ */
+ bool is_bdma;
+#endif
+ /**
+ * @brief Union of the RX DMA streams.
+ */
+ union {
+#if defined(STM32_I2C_DMA_REQUIRED) || defined(__DOXYGEN__)
+ /**
+ * @brief Receive DMA stream.
+ */
+ const stm32_dma_stream_t *dma;
+#endif
+#if (STM32_I2C4_USE_BDMA == TRUE) || defined(__DOXYGEN__)
+#if defined(STM32_BDMA_REQUIRED) || defined(__DOXYGEN__)
+ /**
+ * @brief Receive BDMA stream.
+ */
+ const stm32_bdma_stream_t *bdma;
+#endif
+#endif
+ } rx;
+ /**
+ * @brief Union of the TX DMA streams.
+ */
+ union {
+#if defined(STM32_I2C_DMA_REQUIRED) || defined(__DOXYGEN__)
+ /**
+ * @brief Transmit DMA stream.
+ */
+ const stm32_dma_stream_t *dma;
+#endif
+#if (STM32_I2C4_USE_BDMA == TRUE) || defined(__DOXYGEN__)
+#if defined(STM32_BDMA_REQUIRED) || defined(__DOXYGEN__)
+ /**
+ * @brief Transmit DMA stream.
+ */
+ const stm32_bdma_stream_t *bdma;
+#endif
+#endif
+ } tx;
+#else /* STM32_I2C_USE_DMA == FALSE */
+ /**
+ * @brief Pointer to the next TX buffer location.
+ */
+ const uint8_t *txptr;
+ /**
+ * @brief Pointer to the next RX buffer location.
+ */
+ uint8_t *rxptr;
+#endif /* STM32_I2C_USE_DMA == FALSE */
+ /**
+ * @brief Pointer to the I2Cx registers block.
+ */
+ I2C_TypeDef *i2c;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Get errors from I2C driver.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+#if STM32_I2C_USE_I2C1
+extern I2CDriver I2CD1;
+#endif
+
+#if STM32_I2C_USE_I2C2
+extern I2CDriver I2CD2;
+#endif
+
+#if STM32_I2C_USE_I2C3
+extern I2CDriver I2CD3;
+#endif
+
+#if STM32_I2C_USE_I2C4
+extern I2CDriver I2CD4;
+#endif
+
+#endif /* !defined(__DOXYGEN__) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void i2c_lld_init(void);
+ void i2c_lld_start(I2CDriver *i2cp);
+ void i2c_lld_stop(I2CDriver *i2cp);
+ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ const uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout);
+ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+ uint8_t *rxbuf, size_t rxbytes,
+ sysinterval_t timeout);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_I2C */
+
+#endif /* HAL_I2C_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk new file mode 100644 index 0000000..2964178 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c new file mode 100644 index 0000000..1a62533 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.c @@ -0,0 +1,758 @@ +/*
+ 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 MACv1/hal_mac_lld.c
+ * @brief STM32 low level MAC driver code.
+ *
+ * @addtogroup MAC
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if HAL_USE_MAC || defined(__DOXYGEN__)
+
+#include "hal_mii.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define BUFFER_SIZE ((((STM32_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4)
+
+/* Fixing inconsistencies in ST headers.*/
+#if !defined(ETH_MACMIIAR_CR_Div102) && defined(ETH_MACMIIAR_CR_DIV102)
+#define ETH_MACMIIAR_CR_Div102 ETH_MACMIIAR_CR_DIV102
+#endif
+#if !defined(ETH_MACMIIAR_CR_Div62) && defined(ETH_MACMIIAR_CR_DIV62)
+#define ETH_MACMIIAR_CR_Div62 ETH_MACMIIAR_CR_DIV62
+#endif
+#if !defined(ETH_MACMIIAR_CR_Div42) && defined(ETH_MACMIIAR_CR_DIV42)
+#define ETH_MACMIIAR_CR_Div42 ETH_MACMIIAR_CR_DIV42
+#endif
+#if !defined(ETH_MACMIIAR_CR_Div26) && defined(ETH_MACMIIAR_CR_DIV26)
+#define ETH_MACMIIAR_CR_Div26 ETH_MACMIIAR_CR_DIV26
+#endif
+#if !defined(ETH_MACMIIAR_CR_Div16) && defined(ETH_MACMIIAR_CR_DIV16)
+#define ETH_MACMIIAR_CR_Div16 ETH_MACMIIAR_CR_DIV16
+#endif
+
+/* MII divider optimal value.*/
+#if (STM32_HCLK >= 150000000)
+#define MACMIIDR_CR ETH_MACMIIAR_CR_Div102
+#elif (STM32_HCLK >= 100000000)
+#define MACMIIDR_CR ETH_MACMIIAR_CR_Div62
+#elif (STM32_HCLK >= 60000000)
+#define MACMIIDR_CR ETH_MACMIIAR_CR_Div42
+#elif (STM32_HCLK >= 35000000)
+#define MACMIIDR_CR ETH_MACMIIAR_CR_Div26
+#elif (STM32_HCLK >= 20000000)
+#define MACMIIDR_CR ETH_MACMIIAR_CR_Div16
+#else
+#error "STM32_HCLK below minimum frequency for ETH operations (20MHz)"
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief Ethernet driver 1.
+ */
+MACDriver ETHD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const uint8_t default_mac_address[] = {0xAA, 0x55, 0x13,
+ 0x37, 0x01, 0x10};
+
+static stm32_eth_rx_descriptor_t __eth_rd[STM32_MAC_RECEIVE_BUFFERS];
+static stm32_eth_tx_descriptor_t __eth_td[STM32_MAC_TRANSMIT_BUFFERS];
+
+static uint32_t __eth_rb[STM32_MAC_RECEIVE_BUFFERS][BUFFER_SIZE];
+static uint32_t __eth_tb[STM32_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE];
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Writes a PHY register.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ * @param[in] reg register number
+ * @param[in] value new register value
+ *
+ * @notapi
+ */
+void mii_write(MACDriver *macp, uint32_t reg, uint32_t value) {
+
+ ETH->MACMIIDR = value;
+ ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR |
+ ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
+ while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
+ ;
+}
+
+/**
+ * @brief Reads a PHY register.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ * @param[in] reg register number
+ *
+ * @return The PHY register content.
+ *
+ * @notapi
+ */
+uint32_t mii_read(MACDriver *macp, uint32_t reg) {
+
+ ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | ETH_MACMIIAR_MB;
+ while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
+ ;
+ return ETH->MACMIIDR;
+}
+
+#if !defined(BOARD_PHY_ADDRESS)
+/**
+ * @brief PHY address detection.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ */
+static void mii_find_phy(MACDriver *macp) {
+ uint32_t i;
+
+#if STM32_MAC_PHY_TIMEOUT > 0
+ unsigned n = STM32_MAC_PHY_TIMEOUT;
+ do {
+#endif
+ for (i = 0U; i <= 31U; i++) {
+ macp->phyaddr = i << 11U;
+ ETH->MACMIIDR = (i << 6U) | MACMIIDR_CR;
+ if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) &&
+ ((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) {
+ return;
+ }
+ }
+#if STM32_MAC_PHY_TIMEOUT > 0
+ n--;
+ } while (n > 0U);
+#endif
+ /* Wrong or defective board.*/
+ osalSysHalt("MAC failure");
+}
+#endif
+
+/**
+ * @brief MAC address setup.
+ *
+ * @param[in] p pointer to a six bytes buffer containing the MAC
+ * address
+ */
+static void mac_lld_set_address(const uint8_t *p) {
+
+ /* MAC address configuration, only a single address comparator is used,
+ hash table not used.*/
+ ETH->MACA0HR = ((uint32_t)p[5] << 8) |
+ ((uint32_t)p[4] << 0);
+ ETH->MACA0LR = ((uint32_t)p[3] << 24) |
+ ((uint32_t)p[2] << 16) |
+ ((uint32_t)p[1] << 8) |
+ ((uint32_t)p[0] << 0);
+ ETH->MACA1HR = 0x0000FFFF;
+ ETH->MACA1LR = 0xFFFFFFFF;
+ ETH->MACA2HR = 0x0000FFFF;
+ ETH->MACA2LR = 0xFFFFFFFF;
+ ETH->MACA3HR = 0x0000FFFF;
+ ETH->MACA3LR = 0xFFFFFFFF;
+ ETH->MACHTHR = 0;
+ ETH->MACHTLR = 0;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+OSAL_IRQ_HANDLER(STM32_ETH_HANDLER) {
+ uint32_t dmasr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ dmasr = ETH->DMASR;
+ ETH->DMASR = dmasr; /* Clear status bits.*/
+
+ if (dmasr & ETH_DMASR_RS) {
+ /* Data Received.*/
+ osalSysLockFromISR();
+ osalThreadDequeueAllI(ÐD1.rdqueue, MSG_RESET);
+#if MAC_USE_EVENTS
+ osalEventBroadcastFlagsI(ÐD1.rdevent, 0);
+#endif
+ osalSysUnlockFromISR();
+ }
+
+ if (dmasr & ETH_DMASR_TS) {
+ /* Data Transmitted.*/
+ osalSysLockFromISR();
+ osalThreadDequeueAllI(ÐD1.tdqueue, MSG_RESET);
+ osalSysUnlockFromISR();
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level MAC initialization.
+ *
+ * @notapi
+ */
+void mac_lld_init(void) {
+ unsigned i;
+
+ macObjectInit(ÐD1);
+ ETHD1.link_up = false;
+
+ /* Descriptor tables are initialized in chained mode, note that the first
+ word is not initialized here but in mac_lld_start().*/
+ for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) {
+ __eth_rd[i].rdes1 = STM32_RDES1_RCH | STM32_MAC_BUFFERS_SIZE;
+ __eth_rd[i].rdes2 = (uint32_t)__eth_rb[i];
+ __eth_rd[i].rdes3 = (uint32_t)&__eth_rd[(i + 1) % STM32_MAC_RECEIVE_BUFFERS];
+ }
+ for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) {
+ __eth_td[i].tdes1 = 0;
+ __eth_td[i].tdes2 = (uint32_t)__eth_tb[i];
+ __eth_td[i].tdes3 = (uint32_t)&__eth_td[(i + 1) % STM32_MAC_TRANSMIT_BUFFERS];
+ }
+
+ /* Selection of the RMII or MII mode based on info exported by board.h.*/
+#if defined(STM32F10X_CL)
+#if defined(BOARD_PHY_RMII)
+ AFIO->MAPR |= AFIO_MAPR_MII_RMII_SEL;
+#else
+ AFIO->MAPR &= ~AFIO_MAPR_MII_RMII_SEL;
+#endif
+#elif defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX)
+#if defined(BOARD_PHY_RMII)
+ SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
+#else
+ SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
+#endif
+#else
+#error "unsupported STM32 platform for MAC driver"
+#endif
+
+ /* Reset of the MAC core.*/
+ rccResetETH();
+
+ /* MAC clocks temporary activation.*/
+ rccEnableETH(true);
+
+ /* PHY address setup.*/
+#if defined(BOARD_PHY_ADDRESS)
+ ETHD1.phyaddr = BOARD_PHY_ADDRESS << 11;
+#else
+ mii_find_phy(ÐD1);
+#endif
+
+#if defined(BOARD_PHY_RESET)
+ /* PHY board-specific reset procedure.*/
+ BOARD_PHY_RESET();
+#else
+ /* PHY soft reset procedure.*/
+ mii_write(ÐD1, MII_BMCR, BMCR_RESET);
+#if defined(BOARD_PHY_RESET_DELAY)
+ osalSysPolledDelayX(BOARD_PHY_RESET_DELAY);
+#endif
+ while (mii_read(ÐD1, MII_BMCR) & BMCR_RESET)
+ ;
+#endif
+
+#if STM32_MAC_ETH1_CHANGE_PHY_STATE
+ /* PHY in power down mode until the driver will be started.*/
+ mii_write(ÐD1, MII_BMCR, mii_read(ÐD1, MII_BMCR) | BMCR_PDOWN);
+#endif
+
+ /* MAC clocks stopped again.*/
+ rccDisableETH();
+}
+
+/**
+ * @brief Configures and activates the MAC peripheral.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ *
+ * @notapi
+ */
+void mac_lld_start(MACDriver *macp) {
+ unsigned i;
+
+ /* Resets the state of all descriptors.*/
+ for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++)
+ __eth_rd[i].rdes0 = STM32_RDES0_OWN;
+ macp->rxptr = (stm32_eth_rx_descriptor_t *)__eth_rd;
+ for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++)
+ __eth_td[i].tdes0 = STM32_TDES0_TCH;
+ macp->txptr = (stm32_eth_tx_descriptor_t *)__eth_td;
+
+ /* MAC clocks activation and commanded reset procedure.*/
+ rccEnableETH(true);
+#if defined(STM32_MAC_DMABMR_SR)
+ ETH->DMABMR |= ETH_DMABMR_SR;
+ while (ETH->DMABMR & ETH_DMABMR_SR)
+ ;
+#endif
+
+ /* ISR vector enabled.*/
+ nvicEnableVector(STM32_ETH_NUMBER, STM32_MAC_ETH1_IRQ_PRIORITY);
+
+#if STM32_MAC_ETH1_CHANGE_PHY_STATE
+ /* PHY in power up mode.*/
+ mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN);
+#endif
+
+ /* MAC configuration.*/
+ ETH->MACFFR = 0;
+ ETH->MACFCR = 0;
+ ETH->MACVLANTR = 0;
+
+ /* MAC address setup.*/
+ if (macp->config->mac_address == NULL)
+ mac_lld_set_address(default_mac_address);
+ else
+ mac_lld_set_address(macp->config->mac_address);
+
+ /* Transmitter and receiver enabled.
+ Note that the complete setup of the MAC is performed when the link
+ status is detected.*/
+#if STM32_MAC_IP_CHECKSUM_OFFLOAD
+ ETH->MACCR = ETH_MACCR_IPCO | ETH_MACCR_RE | ETH_MACCR_TE;
+#else
+ ETH->MACCR = ETH_MACCR_RE | ETH_MACCR_TE;
+#endif
+
+ /* DMA configuration:
+ Descriptor chains pointers.*/
+ ETH->DMARDLAR = (uint32_t)__eth_rd;
+ ETH->DMATDLAR = (uint32_t)__eth_td;
+
+ /* Enabling required interrupt sources.*/
+ ETH->DMASR = ETH->DMASR;
+ ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE;
+
+ /* DMA general settings.*/
+ ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_RDP_1Beat | ETH_DMABMR_PBL_1Beat;
+
+ /* Check because errata on some devices. There should be no need to
+ disable flushing because the TXFIFO should be empty on macStart().*/
+#if !defined(STM32_MAC_DISABLE_TX_FLUSH)
+ /* Transmit FIFO flush.*/
+ ETH->DMAOMR = ETH_DMAOMR_FTF;
+ while (ETH->DMAOMR & ETH_DMAOMR_FTF)
+ ;
+#endif
+
+ /* DMA final configuration and start.*/
+ ETH->DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_TSF |
+ ETH_DMAOMR_ST | ETH_DMAOMR_SR;
+}
+
+/**
+ * @brief Deactivates the MAC peripheral.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ *
+ * @notapi
+ */
+void mac_lld_stop(MACDriver *macp) {
+
+ if (macp->state != MAC_STOP) {
+#if STM32_MAC_ETH1_CHANGE_PHY_STATE
+ /* PHY in power down mode until the driver will be restarted.*/
+ mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN);
+#endif
+
+ /* MAC and DMA stopped.*/
+ ETH->MACCR = 0;
+ ETH->DMAOMR = 0;
+ ETH->DMAIER = 0;
+ ETH->DMASR = ETH->DMASR;
+
+ /* MAC clocks stopped.*/
+ rccDisableETH();
+
+ /* ISR vector disabled.*/
+ nvicDisableVector(STM32_ETH_NUMBER);
+ }
+}
+
+/**
+ * @brief Returns a transmission descriptor.
+ * @details One of the available transmission descriptors is locked and
+ * returned.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ * @param[out] tdp pointer to a @p MACTransmitDescriptor structure
+ * @return The operation status.
+ * @retval MSG_OK the descriptor has been obtained.
+ * @retval MSG_TIMEOUT descriptor not available.
+ *
+ * @notapi
+ */
+msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
+ MACTransmitDescriptor *tdp) {
+ stm32_eth_tx_descriptor_t *tdes;
+
+ if (!macp->link_up)
+ return MSG_TIMEOUT;
+
+ /* Get Current TX descriptor.*/
+ tdes = macp->txptr;
+
+ /* Ensure that descriptor isn't owned by the Ethernet DMA or locked by
+ another thread.*/
+ if (tdes->tdes0 & (STM32_TDES0_OWN | STM32_TDES0_LOCKED)) {
+ return MSG_TIMEOUT;
+ }
+
+ /* Marks the current descriptor as locked using a reserved bit.*/
+ tdes->tdes0 |= STM32_TDES0_LOCKED;
+
+ /* Next TX descriptor to use.*/
+ macp->txptr = (stm32_eth_tx_descriptor_t *)tdes->tdes3;
+
+ /* Set the buffer size and configuration.*/
+ tdp->offset = 0;
+ tdp->size = STM32_MAC_BUFFERS_SIZE;
+ tdp->physdesc = tdes;
+
+ return MSG_OK;
+}
+
+/**
+ * @brief Releases a transmit descriptor and starts the transmission of the
+ * enqueued data as a single frame.
+ *
+ * @param[in] tdp the pointer to the @p MACTransmitDescriptor structure
+ *
+ * @notapi
+ */
+void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) {
+
+ osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN),
+ "attempt to release descriptor already owned by DMA");
+
+ osalSysLock();
+
+ /* Unlocks the descriptor and returns it to the DMA engine.*/
+ tdp->physdesc->tdes1 = tdp->offset;
+ tdp->physdesc->tdes0 = STM32_TDES0_CIC(STM32_MAC_IP_CHECKSUM_OFFLOAD) |
+ STM32_TDES0_IC | STM32_TDES0_LS | STM32_TDES0_FS |
+ STM32_TDES0_TCH | STM32_TDES0_OWN;
+
+ /* Wait for the write to tdes0 to go through before resuming the DMA.*/
+ __DSB();
+
+ /* If the DMA engine is stalled then a restart request is issued.*/
+ if ((ETH->DMASR & ETH_DMASR_TPS) == ETH_DMASR_TPS_Suspended) {
+ ETH->DMASR = ETH_DMASR_TBUS;
+ ETH->DMATPDR = ETH_DMASR_TBUS; /* Any value is OK.*/
+ }
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Returns a receive descriptor.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ * @param[out] rdp pointer to a @p MACReceiveDescriptor structure
+ * @return The operation status.
+ * @retval MSG_OK the descriptor has been obtained.
+ * @retval MSG_TIMEOUT descriptor not available.
+ *
+ * @notapi
+ */
+msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
+ MACReceiveDescriptor *rdp) {
+ stm32_eth_rx_descriptor_t *rdes;
+
+ /* Get Current RX descriptor.*/
+ rdes = macp->rxptr;
+
+ /* Iterates through received frames until a valid one is found, invalid
+ frames are discarded.*/
+ while (!(rdes->rdes0 & STM32_RDES0_OWN)) {
+ if (!(rdes->rdes0 & (STM32_RDES0_AFM | STM32_RDES0_ES))
+#if STM32_MAC_IP_CHECKSUM_OFFLOAD
+ && (rdes->rdes0 & STM32_RDES0_FT)
+ && !(rdes->rdes0 & (STM32_RDES0_IPHCE | STM32_RDES0_PCE))
+#endif
+ && (rdes->rdes0 & STM32_RDES0_FS) && (rdes->rdes0 & STM32_RDES0_LS)) {
+ /* Found a valid one.*/
+ rdp->offset = 0;
+ rdp->size = ((rdes->rdes0 & STM32_RDES0_FL_MASK) >> 16) - 4;
+ rdp->physdesc = rdes;
+ macp->rxptr = (stm32_eth_rx_descriptor_t *)rdes->rdes3;
+
+ return MSG_OK;
+ }
+ /* Invalid frame found, purging.*/
+ rdes->rdes0 = STM32_RDES0_OWN;
+ rdes = (stm32_eth_rx_descriptor_t *)rdes->rdes3;
+ }
+
+ /* Next descriptor to check.*/
+ macp->rxptr = rdes;
+
+ return MSG_TIMEOUT;
+}
+
+/**
+ * @brief Releases a receive descriptor.
+ * @details The descriptor and its buffer are made available for more incoming
+ * frames.
+ *
+ * @param[in] rdp the pointer to the @p MACReceiveDescriptor structure
+ *
+ * @notapi
+ */
+void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) {
+
+ osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN),
+ "attempt to release descriptor already owned by DMA");
+
+ osalSysLock();
+
+ /* Give buffer back to the Ethernet DMA.*/
+ rdp->physdesc->rdes0 = STM32_RDES0_OWN;
+
+ /* Wait for the write to rdes0 to go through before resuming the DMA.*/
+ __DSB();
+
+ /* If the DMA engine is stalled then a restart request is issued.*/
+ if ((ETH->DMASR & ETH_DMASR_RPS) == ETH_DMASR_RPS_Suspended) {
+ ETH->DMASR = ETH_DMASR_RBUS;
+ ETH->DMARPDR = ETH_DMASR_RBUS; /* Any value is OK.*/
+ }
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Updates and returns the link status.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ * @return The link status.
+ * @retval true if the link is active.
+ * @retval false if the link is down.
+ *
+ * @notapi
+ */
+bool mac_lld_poll_link_status(MACDriver *macp) {
+ uint32_t maccr, bmsr, bmcr;
+
+ maccr = ETH->MACCR;
+
+ /* PHY CR and SR registers read.*/
+ (void)mii_read(macp, MII_BMSR);
+ bmsr = mii_read(macp, MII_BMSR);
+ bmcr = mii_read(macp, MII_BMCR);
+
+ /* Check on auto-negotiation mode.*/
+ if (bmcr & BMCR_ANENABLE) {
+ uint32_t lpa;
+
+ /* Auto-negotiation must be finished without faults and link established.*/
+ if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) !=
+ (BMSR_LSTATUS | BMSR_ANEGCOMPLETE))
+ return macp->link_up = false;
+
+ /* Auto-negotiation enabled, checks the LPA register.*/
+ lpa = mii_read(macp, MII_LPA);
+
+ /* Check on link speed.*/
+ if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
+ maccr |= ETH_MACCR_FES;
+ else
+ maccr &= ~ETH_MACCR_FES;
+
+ /* Check on link mode.*/
+ if (lpa & (LPA_10FULL | LPA_100FULL))
+ maccr |= ETH_MACCR_DM;
+ else
+ maccr &= ~ETH_MACCR_DM;
+ }
+ else {
+ /* Link must be established.*/
+ if (!(bmsr & BMSR_LSTATUS))
+ return macp->link_up = false;
+
+ /* Check on link speed.*/
+ if (bmcr & BMCR_SPEED100)
+ maccr |= ETH_MACCR_FES;
+ else
+ maccr &= ~ETH_MACCR_FES;
+
+ /* Check on link mode.*/
+ if (bmcr & BMCR_FULLDPLX)
+ maccr |= ETH_MACCR_DM;
+ else
+ maccr &= ~ETH_MACCR_DM;
+ }
+
+ /* Changes the mode in the MAC.*/
+ ETH->MACCR = maccr;
+
+ /* Returns the link status.*/
+ return macp->link_up = true;
+}
+
+/**
+ * @brief Writes to a transmit descriptor's stream.
+ *
+ * @param[in] tdp pointer to a @p MACTransmitDescriptor structure
+ * @param[in] buf pointer to the buffer containing the data to be
+ * written
+ * @param[in] size number of bytes to be written
+ * @return The number of bytes written into the descriptor's
+ * stream, this value can be less than the amount
+ * specified in the parameter @p size if the maximum
+ * frame size is reached.
+ *
+ * @notapi
+ */
+size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
+ uint8_t *buf,
+ size_t size) {
+
+ osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN),
+ "attempt to write descriptor already owned by DMA");
+
+ if (size > tdp->size - tdp->offset)
+ size = tdp->size - tdp->offset;
+
+ if (size > 0) {
+ memcpy((uint8_t *)(tdp->physdesc->tdes2) + tdp->offset, buf, size);
+ tdp->offset += size;
+ }
+ return size;
+}
+
+/**
+ * @brief Reads from a receive descriptor's stream.
+ *
+ * @param[in] rdp pointer to a @p MACReceiveDescriptor structure
+ * @param[in] buf pointer to the buffer that will receive the read data
+ * @param[in] size number of bytes to be read
+ * @return The number of bytes read from the descriptor's
+ * stream, this value can be less than the amount
+ * specified in the parameter @p size if there are
+ * no more bytes to read.
+ *
+ * @notapi
+ */
+size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
+ uint8_t *buf,
+ size_t size) {
+
+ osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN),
+ "attempt to read descriptor already owned by DMA");
+
+ if (size > rdp->size - rdp->offset)
+ size = rdp->size - rdp->offset;
+
+ if (size > 0) {
+ memcpy(buf, (uint8_t *)(rdp->physdesc->rdes2) + rdp->offset, size);
+ rdp->offset += size;
+ }
+ return size;
+}
+
+#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__)
+/**
+ * @brief Returns a pointer to the next transmit buffer in the descriptor
+ * chain.
+ * @note The API guarantees that enough buffers can be requested to fill
+ * a whole frame.
+ *
+ * @param[in] tdp pointer to a @p MACTransmitDescriptor structure
+ * @param[in] size size of the requested buffer. Specify the frame size
+ * on the first call then scale the value down subtracting
+ * the amount of data already copied into the previous
+ * buffers.
+ * @param[out] sizep pointer to variable receiving the buffer size, it is
+ * zero when the last buffer has already been returned.
+ * Note that a returned size lower than the amount
+ * requested means that more buffers must be requested
+ * in order to fill the frame data entirely.
+ * @return Pointer to the returned buffer.
+ * @retval NULL if the buffer chain has been entirely scanned.
+ *
+ * @notapi
+ */
+uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
+ size_t size,
+ size_t *sizep) {
+
+ if (tdp->offset == 0) {
+ *sizep = tdp->size;
+ tdp->offset = size;
+ return (uint8_t *)tdp->physdesc->tdes2;
+ }
+ *sizep = 0;
+ return NULL;
+}
+
+/**
+ * @brief Returns a pointer to the next receive buffer in the descriptor
+ * chain.
+ * @note The API guarantees that the descriptor chain contains a whole
+ * frame.
+ *
+ * @param[in] rdp pointer to a @p MACReceiveDescriptor structure
+ * @param[out] sizep pointer to variable receiving the buffer size, it is
+ * zero when the last buffer has already been returned.
+ * @return Pointer to the returned buffer.
+ * @retval NULL if the buffer chain has been entirely scanned.
+ *
+ * @notapi
+ */
+const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
+ size_t *sizep) {
+
+ if (rdp->size > 0) {
+ *sizep = rdp->size;
+ rdp->offset = rdp->size;
+ rdp->size = 0;
+ return (uint8_t *)rdp->physdesc->rdes2;
+ }
+ *sizep = 0;
+ return NULL;
+}
+#endif /* MAC_USE_ZERO_COPY */
+
+#endif /* HAL_USE_MAC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h new file mode 100644 index 0000000..31ad016 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MACv1/hal_mac_lld.h @@ -0,0 +1,359 @@ +/*
+ 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 MACv1/hal_mac_lld.h
+ * @brief STM32 low level MAC driver header.
+ *
+ * @addtogroup MAC
+ * @{
+ */
+
+#ifndef HAL_MAC_LLD_H
+#define HAL_MAC_LLD_H
+
+#if HAL_USE_MAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief This implementation supports the zero-copy mode API.
+ */
+#define MAC_SUPPORTS_ZERO_COPY TRUE
+
+/**
+ * @name RDES0 constants
+ * @{
+ */
+#define STM32_RDES0_OWN 0x80000000
+#define STM32_RDES0_AFM 0x40000000
+#define STM32_RDES0_FL_MASK 0x3FFF0000
+#define STM32_RDES0_ES 0x00008000
+#define STM32_RDES0_DESERR 0x00004000
+#define STM32_RDES0_SAF 0x00002000
+#define STM32_RDES0_LE 0x00001000
+#define STM32_RDES0_OE 0x00000800
+#define STM32_RDES0_VLAN 0x00000400
+#define STM32_RDES0_FS 0x00000200
+#define STM32_RDES0_LS 0x00000100
+#define STM32_RDES0_IPHCE 0x00000080
+#define STM32_RDES0_LCO 0x00000040
+#define STM32_RDES0_FT 0x00000020
+#define STM32_RDES0_RWT 0x00000010
+#define STM32_RDES0_RE 0x00000008
+#define STM32_RDES0_DE 0x00000004
+#define STM32_RDES0_CE 0x00000002
+#define STM32_RDES0_PCE 0x00000001
+/** @} */
+
+/**
+ * @name RDES1 constants
+ * @{
+ */
+#define STM32_RDES1_DIC 0x80000000
+#define STM32_RDES1_RBS2_MASK 0x1FFF0000
+#define STM32_RDES1_RER 0x00008000
+#define STM32_RDES1_RCH 0x00004000
+#define STM32_RDES1_RBS1_MASK 0x00001FFF
+/** @} */
+
+/**
+ * @name TDES0 constants
+ * @{
+ */
+#define STM32_TDES0_OWN 0x80000000
+#define STM32_TDES0_IC 0x40000000
+#define STM32_TDES0_LS 0x20000000
+#define STM32_TDES0_FS 0x10000000
+#define STM32_TDES0_DC 0x08000000
+#define STM32_TDES0_DP 0x04000000
+#define STM32_TDES0_TTSE 0x02000000
+#define STM32_TDES0_LOCKED 0x01000000 /* NOTE: Pseudo flag. */
+#define STM32_TDES0_CIC_MASK 0x00C00000
+#define STM32_TDES0_CIC(n) ((n) << 22)
+#define STM32_TDES0_TER 0x00200000
+#define STM32_TDES0_TCH 0x00100000
+#define STM32_TDES0_TTSS 0x00020000
+#define STM32_TDES0_IHE 0x00010000
+#define STM32_TDES0_ES 0x00008000
+#define STM32_TDES0_JT 0x00004000
+#define STM32_TDES0_FF 0x00002000
+#define STM32_TDES0_IPE 0x00001000
+#define STM32_TDES0_LCA 0x00000800
+#define STM32_TDES0_NC 0x00000400
+#define STM32_TDES0_LCO 0x00000200
+#define STM32_TDES0_EC 0x00000100
+#define STM32_TDES0_VF 0x00000080
+#define STM32_TDES0_CC_MASK 0x00000078
+#define STM32_TDES0_ED 0x00000004
+#define STM32_TDES0_UF 0x00000002
+#define STM32_TDES0_DB 0x00000001
+/** @} */
+
+/**
+ * @name TDES1 constants
+ * @{
+ */
+#define STM32_TDES1_TBS2_MASK 0x1FFF0000
+#define STM32_TDES1_TBS1_MASK 0x00001FFF
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Number of available transmit buffers.
+ */
+#if !defined(STM32_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__)
+#define STM32_MAC_TRANSMIT_BUFFERS 2
+#endif
+
+/**
+ * @brief Number of available receive buffers.
+ */
+#if !defined(STM32_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__)
+#define STM32_MAC_RECEIVE_BUFFERS 4
+#endif
+
+/**
+ * @brief Maximum supported frame size.
+ */
+#if !defined(STM32_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define STM32_MAC_BUFFERS_SIZE 1522
+#endif
+
+/**
+ * @brief PHY detection timeout.
+ * @details Timeout for PHY address detection, the scan for a PHY is performed
+ * the specified number of times before invoking the failure handler.
+ * This setting applies only if the PHY address is not explicitly
+ * set in the board header file using @p BOARD_PHY_ADDRESS. A zero
+ * value disables the timeout and a single search is performed.
+ */
+#if !defined(STM32_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_MAC_PHY_TIMEOUT 100
+#endif
+
+/**
+ * @brief Change the PHY power state inside the driver.
+ */
+#if !defined(STM32_MAC_ETH1_CHANGE_PHY_STATE) || defined(__DOXYGEN__)
+#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE
+#endif
+
+/**
+ * @brief ETHD1 interrupt priority level setting.
+ */
+#if !defined(STM32_MAC_ETH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_MAC_ETH1_IRQ_PRIORITY 13
+#endif
+
+/**
+ * @brief IP checksum offload.
+ * @details The following modes are available:
+ * - 0 Function disabled.
+ * - 1 Only IP header checksum calculation and insertion are enabled.
+ * - 2 IP header checksum and payload checksum calculation and
+ * insertion are enabled, but pseudo-header checksum is not
+ * calculated in hardware.
+ * - 3 IP Header checksum and payload checksum calculation and
+ * insertion are enabled, and pseudo-header checksum is
+ * calculated in hardware.
+ * .
+ */
+#if !defined(STM32_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__)
+#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of an STM32 Ethernet receive descriptor.
+ */
+typedef struct {
+ volatile uint32_t rdes0;
+ volatile uint32_t rdes1;
+ volatile uint32_t rdes2;
+ volatile uint32_t rdes3;
+} stm32_eth_rx_descriptor_t;
+
+/**
+ * @brief Type of an STM32 Ethernet transmit descriptor.
+ */
+typedef struct {
+ volatile uint32_t tdes0;
+ volatile uint32_t tdes1;
+ volatile uint32_t tdes2;
+ volatile uint32_t tdes3;
+} stm32_eth_tx_descriptor_t;
+
+/**
+ * @brief Driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief MAC address.
+ */
+ uint8_t *mac_address;
+ /* End of the mandatory fields.*/
+} MACConfig;
+
+/**
+ * @brief Structure representing a MAC driver.
+ */
+struct MACDriver {
+ /**
+ * @brief Driver state.
+ */
+ macstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const MACConfig *config;
+ /**
+ * @brief Transmit semaphore.
+ */
+ threads_queue_t tdqueue;
+ /**
+ * @brief Receive semaphore.
+ */
+ threads_queue_t rdqueue;
+#if MAC_USE_EVENTS || defined(__DOXYGEN__)
+ /**
+ * @brief Receive event.
+ */
+ event_source_t rdevent;
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Link status flag.
+ */
+ bool link_up;
+ /**
+ * @brief PHY address (pre shifted).
+ */
+ uint32_t phyaddr;
+ /**
+ * @brief Receive next frame pointer.
+ */
+ stm32_eth_rx_descriptor_t *rxptr;
+ /**
+ * @brief Transmit next frame pointer.
+ */
+ stm32_eth_tx_descriptor_t *txptr;
+};
+
+/**
+ * @brief Structure representing a transmit descriptor.
+ */
+typedef struct {
+ /**
+ * @brief Current write offset.
+ */
+ size_t offset;
+ /**
+ * @brief Available space size.
+ */
+ size_t size;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the physical descriptor.
+ */
+ stm32_eth_tx_descriptor_t *physdesc;
+} MACTransmitDescriptor;
+
+/**
+ * @brief Structure representing a receive descriptor.
+ */
+typedef struct {
+ /**
+ * @brief Current read offset.
+ */
+ size_t offset;
+ /**
+ * @brief Available data size.
+ */
+ size_t size;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the physical descriptor.
+ */
+ stm32_eth_rx_descriptor_t *physdesc;
+} MACReceiveDescriptor;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern MACDriver ETHD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void mii_write(MACDriver *macp, uint32_t reg, uint32_t value);
+ uint32_t mii_read(MACDriver *macp, uint32_t reg);
+ void mac_lld_init(void);
+ void mac_lld_start(MACDriver *macp);
+ void mac_lld_stop(MACDriver *macp);
+ msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
+ MACTransmitDescriptor *tdp);
+ void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp);
+ msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
+ MACReceiveDescriptor *rdp);
+ void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp);
+ bool mac_lld_poll_link_status(MACDriver *macp);
+ size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
+ uint8_t *buf,
+ size_t size);
+ size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
+ uint8_t *buf,
+ size_t size);
+#if MAC_USE_ZERO_COPY
+ uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
+ size_t size,
+ size_t *sizep);
+ const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
+ size_t *sizep);
+#endif /* MAC_USE_ZERO_COPY */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_MAC */
+
+#endif /* HAL_MAC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk new file mode 100644 index 0000000..d10e2ad --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/driver.mk @@ -0,0 +1,2 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt new file mode 100644 index 0000000..a092556 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/notes.txt @@ -0,0 +1,11 @@ +STM32 MDMAv1 driver.
+
+Driver capability:
+
+- The driver supports the STM32 complex MDMA controller found on H7
+ sub-family.
+
+The file registry must export:
+
+STM32_MDMA_CHn_HANDLER - Vector name for channel "n" (0..15).
+STM32_MDMA_CHn_NUMBER - Vector number for channel "n" (0..15).
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c new file mode 100644 index 0000000..c77bfa0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.c @@ -0,0 +1,355 @@ +/*
+ 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 MDMAv1/stm32_mdma.c
+ * @brief MDMA helper driver code.
+ *
+ * @addtogroup STM32_MDMA
+ * @details MDMA sharing helper driver. In the STM32 the MDMA channels are a
+ * shared resource, this driver allows to allocate and free MDMA
+ * STM32 at runtime in order to allow all the other device
+ * drivers to coordinate the access to the resource.
+ * @note The MDMA ISR handlers are all declared into this module because
+ * sharing, the various device drivers can associate a callback to
+ * ISRs when allocating channels.
+ * @{
+ */
+
+#include "hal.h"
+
+/* The following macro is only defined if some driver requiring MDMA services
+ has been enabled.*/
+#if defined(STM32_MDMA_REQUIRED) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Global MDMA-related data structures.
+ */
+static struct {
+ /**
+ * @brief Mask of the allocated channels.
+ */
+ uint32_t allocated_mask;
+ /**
+ * @brief MDMA IRQ redirectors.
+ */
+ stm32_mdma_channel_t channels[STM32_MDMA_CHANNELS];
+} mdma;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static void mdma_serve_interrupt(const stm32_mdma_channel_t *mdmachp) {
+ uint32_t flags;
+
+ flags = mdmachp->channel->CISR;
+ mdmachp->channel->CIFCR = flags;
+ if (mdmachp->func != NULL) {
+ mdmachp->func(mdmachp->param, flags);
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief MDMA shared interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_MDMA_HANDLER) {
+ uint32_t gisr = MDMA->GISR0;
+ OSAL_IRQ_PROLOGUE();
+
+ if ((gisr & (1U << 0)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[0]);
+ }
+
+ if ((gisr & (1U << 1)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[1]);
+ }
+
+ if ((gisr & (1U << 2)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[2]);
+ }
+
+ if ((gisr & (1U << 3)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[3]);
+ }
+
+ if ((gisr & (1U << 4)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[4]);
+ }
+
+ if ((gisr & (1U << 5)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[5]);
+ }
+
+ if ((gisr & (1U << 6)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[6]);
+ }
+
+ if ((gisr & (1U << 7)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[7]);
+ }
+
+ if ((gisr & (1U << 8)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[8]);
+ }
+
+ if ((gisr & (1U << 9)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[9]);
+ }
+
+ if ((gisr & (1U << 10)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[10]);
+ }
+
+ if ((gisr & (1U << 11)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[11]);
+ }
+
+ if ((gisr & (1U << 12)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[12]);
+ }
+
+ if ((gisr & (1U << 13)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[13]);
+ }
+
+ if ((gisr & (1U << 14)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[14]);
+ }
+
+ if ((gisr & (1U << 15)) != 0U) {
+ mdma_serve_interrupt(&mdma.channels[15]);
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 MDMA helper initialization.
+ *
+ * @init
+ */
+void mdmaInit(void) {
+ static MDMA_Channel_TypeDef * const ch[STM32_MDMA_CHANNELS] = {
+ MDMA_Channel0, MDMA_Channel1, MDMA_Channel2, MDMA_Channel3,
+ MDMA_Channel4, MDMA_Channel5, MDMA_Channel6, MDMA_Channel7,
+ MDMA_Channel8, MDMA_Channel9, MDMA_Channel10, MDMA_Channel11,
+ MDMA_Channel12, MDMA_Channel13, MDMA_Channel14, MDMA_Channel15
+ };
+ unsigned i;
+
+ mdma.allocated_mask = 0U;
+ for (i = 0U; i < STM32_MDMA_CHANNELS; i++) {
+ MDMA_Channel_TypeDef *cp = ch[i];
+ mdma.channels[i].channel = cp;
+ mdma.channels[i].func = NULL;
+ mdma.channels[i].channel->CCR = STM32_MDMA_CCR_RESET_VALUE;
+ mdma.channels[i].channel->CTCR = STM32_MDMA_CTCR_RESET_VALUE;
+ mdma.channels[i].channel->CIFCR = STM32_MDMA_CIFCR_CTEIF |
+ STM32_MDMA_CIFCR_CBRTIF |
+ STM32_MDMA_CIFCR_CBRTIF |
+ STM32_MDMA_CIFCR_CCTCIF |
+ STM32_MDMA_CIFCR_CTEIF;
+ }
+}
+
+/**
+ * @brief Allocates an MDMA channel.
+ * @details The channel is allocated and, if required, the MDMA clock enabled.
+ * The function also enables the IRQ vector associated to the channel
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific channel or:
+ * - @p STM32_MDMA_CHANNEL_ID_ANY for any channel.
+ * .
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_mdma_channel_t
+ * structure.
+ * @retval NULL if a/the channel is not available.
+ *
+ * @iclass
+ */
+const stm32_mdma_channel_t *dmaChannelAllocI(uint32_t id,
+ stm32_mdmaisr_t func,
+ void *param) {
+ uint32_t i, startid, endid;
+
+ osalDbgCheckClassI();
+
+ if (id < STM32_MDMA_CHANNELS) {
+ startid = id;
+ endid = id;
+ }
+ else if (id == STM32_MDMA_CHANNEL_ID_ANY) {
+ startid = 0U;
+ endid = STM32_MDMA_CHANNELS - 1U;
+ }
+ else {
+ osalDbgCheck(false);
+ return NULL;
+ }
+
+ for (i = startid; i <= endid; i++) {
+ uint32_t mask = (1U << i);
+ if ((mdma.allocated_mask & mask) == 0U) {
+ stm32_mdma_channel_t *mdmachp = &mdma.channels[i];
+
+ /* Installs the MDMA handler.*/
+ mdma.allocated_mask |= mask;
+ mdmachp->func = func;
+ mdmachp->param = param;
+
+ /* Enabling MDMA clocks required by the current channels set.*/
+ if (mdma.allocated_mask != 0U) {
+ rccEnableMDMA(true);
+ }
+
+ return mdmachp;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Allocates a MDMA channel.
+ * @details The channel is allocated and, if required, the MDMA clock enabled.
+ * The function also enables the IRQ vector associated to the channel
+ * and initializes its priority.
+ *
+ * @param[in] id numeric identifiers of a specific channel or:
+ * - @p STM32_MDMA_CHANNEL_ID_ANY for any channel.
+ * .
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return Pointer to the allocated @p stm32_mdma_channel_t
+ * structure.
+ * @retval NULL if a/the channel is not available.
+ *
+ * @api
+ */
+const stm32_mdma_channel_t *dmaChannelAlloc(uint32_t id,
+ stm32_mdmaisr_t func,
+ void *param) {
+ const stm32_mdma_channel_t *mdmachp;
+
+ osalSysLock();
+ mdmachp = mdmaChannelAllocI(id, func, param);
+ osalSysUnlock();
+
+ return mdmachp;
+}
+
+/**
+ * @brief Releases a MDMA channel.
+ * @details The channel is freed and, if required, the MDMA clock disabled.
+ * Trying to release a unallocated channel is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ *
+ * @iclass
+ */
+void mdmaChannelFreeI(const stm32_mdma_channel_t *mdmachp) {
+ uint32_t channel = mdmachp - mdma.channels;
+ osalDbgCheck(mdmachp != NULL);
+
+ /* Check if the channels is not taken.*/
+ osalDbgAssert((mdma.allocated_mask & (1U << channel)) != 0U,
+ "not allocated");
+
+ /* Marks the channel as not allocated.*/
+ mdma.allocated_mask &= ~(1U << channel);
+
+ /* Shutting down clocks that are no more required, if any.*/
+ if (mdma.allocated_mask == 0U) {
+ rccDisableMDMA();
+ }
+}
+
+/**
+ * @brief Releases a MDMA channel.
+ * @details The channel is freed and, if required, the MDMA clock disabled.
+ * Trying to release a unallocated channel is an illegal operation
+ * and is trapped if assertions are enabled.
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ *
+ * @api
+ */
+void mdmaChannelFree(const stm32_mdma_channel_t *mdmachp) {
+
+ osalSysLock();
+ mdmaChannelFreeI(mdmachp);
+ osalSysUnlock();
+}
+
+/**
+ * @brief MDMA stream disable.
+ * @details The function disables the specified stream, waits for the disable
+ * operation to complete and then clears any pending interrupt.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ *
+ * @xclass
+ */
+void mdmaChannelDisableX(const stm32_mdma_channel_t *mdmachp) {
+ uint32_t ccr = mdmachp->channel->CCR;
+
+ /* Clearing CCR regardless of previous state.*/
+ mdmachp->channel->CCR &= ~(STM32_MDMA_CCR_TCIE | STM32_MDMA_CCR_BTIE |
+ STM32_MDMA_CCR_BRTIE | STM32_MDMA_CCR_CTCIE |
+ STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_EN);
+
+ /* If the channel was enabled then waiting for ongoing operations
+ to finish.*/
+ if ((ccr & STM32_MDMA_CCR_EN) != 0U) {
+ while (((mdmachp)->channel->CISR & STM32_MDMA_CISR_CTCIF) == 0U)
+ ;
+ }
+
+ /* Clearing IRQ sources.*/
+ mdmaChannelClearInterruptX(mdmachp);
+}
+
+#endif /* defined(STM32_MDMA_REQUIRED) */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h new file mode 100644 index 0000000..6dfe9eb --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/MDMAv1/stm32_mdma.h @@ -0,0 +1,448 @@ +/*
+ ChibiOS - Copyright (C) 2006..2019 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 MDMAv1/stm32_mdma.h
+ * @brief MDMA helper driver header.
+ *
+ * @addtogroup STM32_MDMA
+ * @{
+ */
+
+#ifndef STM32_MDMA_H
+#define STM32_MDMA_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Total number of MDMA streams.
+ */
+#define STM32_MDMA_CHANNELS 16U
+
+/**
+ * @brief Mask of the ISR bits passed to the MDMA callback functions.
+ */
+#define STM32_MDMA_ISR_MASK 0x1FU
+
+/**
+ * @brief Checks if a MDMA priority is within the valid range.
+ * @param[in] prio MDMA priority
+ *
+ * @retval The check result.
+ * @retval false invalid MDMA priority.
+ * @retval true correct MDMA priority.
+ */
+#define STM32_MDMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U))
+
+/**
+ * @brief Checks if a MDMA channel id is within the valid range.
+ *
+ * @param[in] id MDMA channel id
+ * @retval The check result.
+ * @retval false invalid MDMA channel.
+ * @retval true correct MDMA channel.
+ */
+#define STM32_MDMA_IS_VALID_CHANNEL(id) (((id) >= 0U) && \
+ ((id) <= STM32_MDMA_CHANNELS))
+
+/**
+ * @brief Special stream identifier
+ */
+#define STM32_MDMA_CHANNEL_ID_ANY STM32_MDMA_CHANNELS
+
+/**
+ * @name CISR register constants
+ * @{
+ */
+#define STM32_MDMA_CISR_TEIF (1U << 0)
+#define STM32_MDMA_CISR_CTCIF (1U << 1)
+#define STM32_MDMA_CISR_BRTIF (1U << 2)
+#define STM32_MDMA_CISR_BTIF (1U << 3)
+#define STM32_MDMA_CISR_TCIF (1U << 4)
+#define STM32_MDMA_CISR_CRQA (1U << 16)
+/** @} */
+
+/**
+ * @name CIFCR register constants
+ * @{
+ */
+#define STM32_MDMA_CIFCR_CTEIF (1U << 0)
+#define STM32_MDMA_CIFCR_CCTCIF (1U << 1)
+#define STM32_MDMA_CIFCR_CBRTIF (1U << 2)
+#define STM32_MDMA_CIFCR_CBTIF (1U << 3)
+#define STM32_MDMA_CIFCR_CTCIF (1U << 4)
+/** @} */
+
+/**
+ * @name CESR register constants
+ * @{
+ */
+#define STM32_MDMA_CESR_TEA_MASK (127U << 0)
+#define STM32_MDMA_CESR_TED (1U << 7)
+#define STM32_MDMA_CESR_TELD (1U << 8)
+#define STM32_MDMA_CESR_TEMD (1U << 9)
+#define STM32_MDMA_CESR_ASE (1U << 10)
+#define STM32_MDMA_CESR_BSE (1U << 11)
+/** @} */
+
+/**
+ * @name CCR register constants
+ * @{
+ */
+#define STM32_MDMA_CCR_RESET_VALUE 0x00000000U
+#define STM32_MDMA_CCR_EN (1U << 0)
+#define STM32_MDMA_CCR_TEIE (1U << 1)
+#define STM32_MDMA_CCR_CTCIE (1U << 2)
+#define STM32_MDMA_CCR_BRTIE (1U << 3)
+#define STM32_MDMA_CCR_BTIE (1U << 4)
+#define STM32_MDMA_CCR_TCIE (1U << 5)
+#define STM32_MDMA_CCR_PL_MASK (3U << 6)
+#define STM32_MDMA_CCR_PL(n) ((n) << 6)
+#define STM32_MDMA_CCR_BEX (1U << 12)
+#define STM32_MDMA_CCR_HEX (1U << 13)
+#define STM32_MDMA_CCR_WEX (1U << 14)
+#define STM32_MDMA_CCR_SWRQ (1U << 16)
+/** @} */
+
+/**
+ * @name CTCR register constants
+ * @{
+ */
+#define STM32_MDMA_CTCR_RESET_VALUE 0x00000000U
+
+#define STM32_MDMA_CTCR_SINC_MASK (3U << 0)
+#define STM32_MDMA_CTCR_SINC(n) ((n) << 0)
+#define STM32_MDMA_CTCR_SINC_FIXED STM32_MDMA_CTCR_SINC(0U)
+#define STM32_MDMA_CTCR_SINC_INC STM32_MDMA_CTCR_SINC(1U)
+#define STM32_MDMA_CTCR_SINC_DEC STM32_MDMA_CTCR_SINC(3U)
+
+#define STM32_MDMA_CTCR_DINC_MASK (3U << 2)
+#define STM32_MDMA_CTCR_DINC(n) ((n) << 2)
+#define STM32_MDMA_CTCR_DINC_FIXED STM32_MDMA_CTCR_DINC(0U)
+#define STM32_MDMA_CTCR_DINC_INC STM32_MDMA_CTCR_DINC(1U)
+#define STM32_MDMA_CTCR_DINC_DEC STM32_MDMA_CTCR_DINC(3U)
+
+#define STM32_MDMA_CTCR_SSIZE_MASK (3U << 4)
+#define STM32_MDMA_CTCR_SSIZE(n) ((n) << 4)
+#define STM32_MDMA_CTCR_SSIZE_BYTE STM32_MDMA_CTCR_SSIZE(0U)
+#define STM32_MDMA_CTCR_SSIZE_HALF STM32_MDMA_CTCR_SSIZE(1U)
+#define STM32_MDMA_CTCR_SSIZE_WORD STM32_MDMA_CTCR_SSIZE(2U)
+#define STM32_MDMA_CTCR_SSIZE_DWORD STM32_MDMA_CTCR_SSIZE(3U)
+
+#define STM32_MDMA_CTCR_DSIZE_MASK (3U << 6)
+#define STM32_MDMA_CTCR_DSIZE(n) ((n) << 6)
+#define STM32_MDMA_CTCR_DSIZE_BYTE STM32_MDMA_CTCR_DSIZE(0U)
+#define STM32_MDMA_CTCR_DSIZE_HALF STM32_MDMA_CTCR_DSIZE(1U)
+#define STM32_MDMA_CTCR_DSIZE_WORD STM32_MDMA_CTCR_DSIZE(2U)
+#define STM32_MDMA_CTCR_DSIZE_DWORD STM32_MDMA_CTCR_DSIZE(3U)
+
+#define STM32_MDMA_CTCR_SINCOS_MASK (3U << 8)
+#define STM32_MDMA_CTCR_SINCOS(n) ((n) << 8)
+#define STM32_MDMA_CTCR_SINCOS_BYTE STM32_MDMA_CTCR_SINCOS(0U)
+#define STM32_MDMA_CTCR_SINCOS_HALF STM32_MDMA_CTCR_SINCOS(1U)
+#define STM32_MDMA_CTCR_SINCOS_WORD STM32_MDMA_CTCR_SINCOS(2U)
+#define STM32_MDMA_CTCR_SINCOS_DWORD STM32_MDMA_CTCR_SINCOS(3U)
+
+#define STM32_MDMA_CTCR_DINCOS_MASK (3U << 10)
+#define STM32_MDMA_CTCR_DINCOS(n) ((n) << 10)
+#define STM32_MDMA_CTCR_DINCOS_BYTE STM32_MDMA_CTCR_DINCOS(0U)
+#define STM32_MDMA_CTCR_DINCOS_HALF STM32_MDMA_CTCR_DINCOS(1U)
+#define STM32_MDMA_CTCR_DINCOS_WORD STM32_MDMA_CTCR_DINCOS(2U)
+#define STM32_MDMA_CTCR_DINCOS_DWORD STM32_MDMA_CTCR_DINCOS(3U)
+
+#define STM32_MDMA_CTCR_SBURST_MASK (7U << 12)
+#define STM32_MDMA_CTCR_SBURST(n) ((n) << 12)
+#define STM32_MDMA_CTCR_SBURST_1 STM32_MDMA_CTCR_SBURST(0U)
+#define STM32_MDMA_CTCR_SBURST_2 STM32_MDMA_CTCR_SBURST(1U)
+#define STM32_MDMA_CTCR_SBURST_4 STM32_MDMA_CTCR_SBURST(2U)
+#define STM32_MDMA_CTCR_SBURST_8 STM32_MDMA_CTCR_SBURST(3U)
+#define STM32_MDMA_CTCR_SBURST_16 STM32_MDMA_CTCR_SBURST(4U)
+#define STM32_MDMA_CTCR_SBURST_32 STM32_MDMA_CTCR_SBURST(5U)
+#define STM32_MDMA_CTCR_SBURST_64 STM32_MDMA_CTCR_SBURST(6U)
+#define STM32_MDMA_CTCR_SBURST_128 STM32_MDMA_CTCR_SBURST(7U)
+
+#define STM32_MDMA_CTCR_DBURST_MASK (7U << 15)
+#define STM32_MDMA_CTCR_DBURST(n) ((n) << 15)
+#define STM32_MDMA_CTCR_DBURST_1 STM32_MDMA_CTCR_DBURST(0U)
+#define STM32_MDMA_CTCR_DBURST_2 STM32_MDMA_CTCR_DBURST(1U)
+#define STM32_MDMA_CTCR_DBURST_4 STM32_MDMA_CTCR_DBURST(2U)
+#define STM32_MDMA_CTCR_DBURST_8 STM32_MDMA_CTCR_DBURST(3U)
+#define STM32_MDMA_CTCR_DBURST_16 STM32_MDMA_CTCR_DBURST(4U)
+#define STM32_MDMA_CTCR_DBURST_32 STM32_MDMA_CTCR_DBURST(5U)
+#define STM32_MDMA_CTCR_DBURST_64 STM32_MDMA_CTCR_DBURST(6U)
+#define STM32_MDMA_CTCR_DBURST_128 STM32_MDMA_CTCR_DBURST(7U)
+
+#define STM32_MDMA_CTCR_TLEN_MASK (127U << 18)
+#define STM32_MDMA_CTCR_TLEN(n) ((n) << 18)
+
+#define STM32_MDMA_CTCR_PKE (1U << 25)
+
+#define STM32_MDMA_CTCR_PAM_MASK (3U << 26)
+#define STM32_MDMA_CTCR_PAM(n) ((n) << 26)
+#define STM32_MDMA_CTCR_PAM_RIGHT STM32_MDMA_CTCR_PAM(0U)
+#define STM32_MDMA_CTCR_PAM_RIGHT_SE STM32_MDMA_CTCR_PAM(1U)
+#define STM32_MDMA_CTCR_PAM_LEFT STM32_MDMA_CTCR_PAM(2U)
+
+#define STM32_MDMA_CTCR_TRGM_MASK (3U << 28)
+#define STM32_MDMA_CTCR_TRGM(n) ((n) << 28)
+#define STM32_MDMA_CTCR_TRGM_BUFFER STM32_MDMA_CTCR_TRGM(0U)
+#define STM32_MDMA_CTCR_TRGM_BLOCK STM32_MDMA_CTCR_TRGM(1U)
+#define STM32_MDMA_CTCR_TRGM_REP_BLOCK STM32_MDMA_CTCR_TRGM(2U)
+#define STM32_MDMA_CTCR_TRGM_WHOLE STM32_MDMA_CTCR_TRGM(3U)
+
+#define STM32_MDMA_CTCR_SWRM (1U << 30)
+
+#define STM32_MDMA_CTCR_BWM_MASK (1U << 31)
+#define STM32_MDMA_CTCR_BWM_NON_BUFF (0U << 31)
+#define STM32_MDMA_CTCR_BWM_BUFF (1U << 31)
+/** @} */
+
+/**
+ * @name BNDTR register constants
+ * @{
+ */
+#define STM32_MDMA_CBNDTR_BNDT_MASK (0x1FFFFU << 0)
+#define STM32_MDMA_CBNDTR_BNDT(n) ((n) << 0)
+#define STM32_MDMA_CBNDTR_BRSUM (1U << 18)
+#define STM32_MDMA_CBNDTR_BRDUM (1U << 19)
+#define STM32_MDMA_CBNDTR_BRC_MASK (0xFFFU << 20)
+#define STM32_MDMA_CBNDTR_BRC(n) ((n) << 20)
+/** @} */
+
+/**
+ * @name CBRUR register constants
+ * @{
+ */
+#define STM32_MDMA_CBRUR_SUV_MASK (0xFFFFU << 0)
+#define STM32_MDMA_CBRUR_SUV(n) ((n) << 0)
+#define STM32_MDMA_CBRUR_DUV_MASK (0xFFFFU << 16)
+#define STM32_MDMA_CBRUR_DUV(n) ((n) << 16)
+/** @} */
+
+/**
+ * @name CTBR register constants
+ * @{
+ */
+#define STM32_MDMA_CTBR_TSEL_MASK (0x3FU << 0)
+#define STM32_MDMA_CTBR_TSEL(n) ((n) << 0)
+#define STM32_MDMA_CTBR_TSEL_SBUS (1U << 16)
+#define STM32_MDMA_CTBR_TSEL_DBUS (1U << 17)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_MDMA_HANDLER)
+#error "STM32_MDMA_HANDLER missing in registry"
+#endif
+
+#if !defined(STM32_MDMA_NUMBER)
+#error "STM32_MDMA_NUMBER missing in registry"
+#endif
+
+/* Priority settings checks.*/
+#if !defined(STM32_IRQ_MDMA_PRIORITY)
+#error "STM32_IRQ_MDMA_PRIORITY not defined in mcuconf.h"
+#endif
+
+#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_MDMA_PRIORITY)
+#error "Invalid IRQ priority assigned to STM32_IRQ_MDMA_PRIORITY"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 MDMA ISR function type.
+ *
+ * @param[in] p parameter for the registered function
+ * @param[in] flags content of the CISR register
+ */
+typedef void (*stm32_mdmaisr_t)(void *p, uint32_t flags);
+
+/**
+ * @brief STM32 MDMA stream descriptor structure.
+ */
+typedef struct {
+ /**
+ * @brief Associated MDMA channel.
+ */
+ MDMA_Channel_TypeDef *channel;
+ /**
+ * @brief MDMA callback function.
+ */
+ stm32_mdmaisr_t func;
+ /**
+ * @brief MDMA callback parameter.
+ */
+ void *param;
+} stm32_mdma_channel_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Associates a source address to a MDMA stream.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ * @param[in] addr value to be written in the CSAR register
+ *
+ * @xclass
+ */
+#define mdmaChannelSetSourceX(mdmachp, addr) do { \
+ (mdmachp)->channel->CSAR = (uint32_t)(addr); \
+} while (0)
+
+/**
+ * @brief Associates a memory destination to a MDMA stream.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ * @param[in] addr value to be written in the CDAR register
+ *
+ * @xclass
+ */
+#define mdmaChannelSetDestinationX(mdmachp, addr) do { \
+ (mdmachp)->channel->CDAR = (uint32_t)(addr); \
+} while (0)
+
+/**
+ * @brief Sets parameters related to the transaction size.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ * @param[in] size number of bytes per block
+ * @param[in] n number of blocks repetitions
+ * @param[in] opt other option bits for the CBNDTR register
+ *
+ * @xclass
+ */
+#define mdmaChannelSetTransactionSizeX(mdmachp, size, n, opt) do { \
+ (mdmachp)->channel->CBNDTR = (uint32_t)STM32_MDMA_CBNDTR_BNDT(size) | \
+ (uint32_t)STM32_MDMA_CBNDTR_BRC(n) | \
+ (uint32_t)opt; \
+} while (0)
+
+/**
+ * @brief Programs the stream mode settings.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ * @param[in] ctcr value to be written in the CTCR register
+ * @param[in] ccr value to be written in the CCR register
+ *
+ * @xclass
+ */
+#define mdmaChannelSetModeX(mdmachp, ctcr, ccr) do { \
+ (mdmachp)->channel->CTCR = (uint32_t)(ctcr); \
+ (mdmachp)->channel->CCR = (uint32_t)(ccr); \
+} while (0)
+
+/**
+ * @brief MDMA stream enable.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ *
+ * @xclass
+ */
+#define mdmaChannelEnableX(mdmachp) do { \
+ (mdmachp)->channel->CCR |= STM32_MDMA_CCR_EN; \
+} while (0)
+
+/**
+ * @brief Channel enable check.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ */
+#define mdmaChannelIsEnabled(mdmachp) \
+ (((mdmachp)->channel->CCR & STM32_MDMA_CCR_EN) != 0U)
+
+/**
+ * @brief MDMA stream interrupt sources clear.
+ * @pre The stream must have been allocated using @p mdmaChannelAlloc().
+ * @post After use the stream can be released using @p mdmaChannelFree().
+ *
+ * @param[in] mdmachp pointer to a stm32_mdma_channel_t structure
+ *
+ * @xclass
+ */
+#define mdmaChannelClearInterruptX(mdmachp) do { \
+ (mdmachp)->channel->CIFCR = (STM32_MDMA_CIFCR_CTEIF | \
+ STM32_MDMA_CIFCR_CBRTIF | \
+ STM32_MDMA_CIFCR_CBRTIF | \
+ STM32_MDMA_CIFCR_CCTCIF | \
+ STM32_MDMA_CIFCR_CTEIF); \
+} while (0)
+
+/**
+ * @brief MDMA IRQ enable.
+ */
+#define mdma_irq_init() \
+ nvicEnableVector(STM32_MDMA_NUMBER, STM32_IRQ_MDMA_PRIORITY)
+
+/**
+ * @brief MDMA IRQ disable.
+ */
+#define mdma_irq_deinit() \
+ nvicDisableVector(STM32_MDMA_NUMBER)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void mdmaInit(void);
+ const stm32_mdma_channel_t *mdmaChannelAllocI(uint32_t id,
+ stm32_mdmaisr_t func,
+ void *param);
+ const stm32_mdma_channel_t *mdmaChannelAlloc(uint32_t id,
+ stm32_mdmaisr_t func,
+ void *param);
+ void mdmaChannelFreeI(const stm32_mdma_channel_t *mdmachp);
+ void mdmaChannelFree(const stm32_mdma_channel_t *mdmachp);
+ void mdmaChannelDisableX(const stm32_mdma_channel_t *mdmachp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_MDMA_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk new file mode 100644 index 0000000..987220b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_WSPI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OCTOSPIv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c new file mode 100644 index 0000000..c71e38a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.c @@ -0,0 +1,464 @@ +/*
+ 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 OCTOSPIv1/hal_wspi_lld.c
+ * @brief STM32 WSPI subsystem low level driver source.
+ *
+ * @addtogroup WSPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* Workarounds for bugs in ST headers.*/
+#if !defined(OCTOSPI_FCR_CTOF) && defined(OCTOSPI_FCR_TOF)
+#define OCTOSPI_FCR_CTOF OCTOSPI_FCR_TOF
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief OCTOSPI1 driver identifier.*/
+#if STM32_WSPI_USE_OCTOSPI1 || defined(__DOXYGEN__)
+WSPIDriver WSPID1;
+#endif
+
+/** @brief OCTOSPI2 driver identifier.*/
+#if STM32_WSPI_USE_OCTOSPI2 || defined(__DOXYGEN__)
+WSPIDriver WSPID2;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Waits for completion of previous operation.
+ */
+static inline void wspi_lld_sync(WSPIDriver *wspip) {
+
+ while ((wspip->ospi->SR & OCTOSPI_SR_BUSY) != 0U) {
+ }
+}
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void wspi_lld_serve_dma_interrupt(WSPIDriver *wspip, uint32_t flags) {
+
+ (void)wspip;
+ (void)flags;
+
+ /* DMA errors handling.*/
+#if defined(STM32_WSPI_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_WSPI_DMA_ERROR_HOOK(wspip);
+ }
+#endif
+}
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ */
+static void wspi_lld_serve_interrupt(WSPIDriver *wspip) {
+
+ /* Portable WSPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _wspi_isr_code(wspip);
+
+ /* Stop everything, we need to give DMA enough time to complete the ongoing
+ operation. Race condition hidden here.*/
+ while (dmaStreamGetTransactionSize(wspip->dma) > 0U)
+ ;
+ dmaStreamDisable(wspip->dma);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_WSPI_USE_OCTOSPI1 || defined(__DOXYGEN__)
+#if !defined(STM32_OCTOSPI1_SUPPRESS_ISR)
+#if !defined(STM32_OCTOSPI1_HANDLER)
+#error "STM32_OCTOSPI1_HANDLER not defined"
+#endif
+/**
+ * @brief STM32_OCTOSPI1_HANDLER interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_OCTOSPI1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ OCTOSPI1->FCR = OCTOSPI_FCR_CTEF | OCTOSPI_FCR_CTCF |
+ OCTOSPI_FCR_CSMF | OCTOSPI_FCR_CTOF;
+
+ wspi_lld_serve_interrupt(&WSPID1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_OCTOSPI1_SUPPRESS_ISR) */
+#endif /* STM32_WSPI_USE_OCTOSPI1 */
+
+#if STM32_WSPI_USE_OCTOSPI2 || defined(__DOXYGEN__)
+#if !defined(STM32_OCTOSPI2_SUPPRESS_ISR)
+#if !defined(STM32_OCTOSPI2_HANDLER)
+#error "STM32_OCTOSPI2_HANDLER not defined"
+#endif
+/**
+ * @brief STM32_OCTOSPI2_HANDLER interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_OCTOSPI2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ OCTOSPI2->FCR = OCTOSPI_FCR_CTEF | OCTOSPI_FCR_CTCF |
+ OCTOSPI_FCR_CSMF | OCTOSPI_FCR_CTOF;
+
+ wspi_lld_serve_interrupt(&WSPID2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_OCTOSPI2_SUPPRESS_ISR) */
+#endif /* STM32_WSPI_USE_OCTOSPI2 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level WSPI driver initialization.
+ *
+ * @notapi
+ */
+void wspi_lld_init(void) {
+
+#if STM32_WSPI_USE_OCTOSPI1
+ wspiObjectInit(&WSPID1);
+ WSPID1.ospi = OCTOSPI1;
+ WSPID1.dma = NULL;
+ WSPID1.dmamode = STM32_DMA_CR_CHSEL(OCTOSPI1_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_WSPI_OCTOSPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_BYTE |
+ STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ nvicEnableVector(STM32_OCTOSPI1_NUMBER, STM32_WSPI_OCTOSPI1_IRQ_PRIORITY);
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2
+ wspiObjectInit(&WSPID2);
+ WSPID2.ospi = OCTOSPI2;
+ WSPID2.dma = NULL;
+ WSPID2.dmamode = STM32_DMA_CR_CHSEL(OCTOSPI2_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_WSPI_OCTOSPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_BYTE |
+ STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ nvicEnableVector(STM32_OCTOSPI2_NUMBER, STM32_WSPI_OCTOSPI2_IRQ_PRIORITY);
+#endif
+}
+
+/**
+ * @brief Configures and activates the WSPI peripheral.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_start(WSPIDriver *wspip) {
+
+ /* If in stopped state then full initialization.*/
+ if (wspip->state == WSPI_STOP) {
+#if STM32_WSPI_USE_OCTOSPI1
+ if (&WSPID1 == wspip) {
+ wspip->dma = dmaStreamAllocI(STM32_WSPI_OCTOSPI1_DMA_STREAM,
+ STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)wspi_lld_serve_dma_interrupt,
+ (void *)wspip);
+ osalDbgAssert(wspip->dma != NULL, "unable to allocate stream");
+ rccEnableOCTOSPI1(true);
+ dmaSetRequestSource(wspip->dma, STM32_DMAMUX1_OCTOSPI1);
+ }
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2
+ if (&WSPID2 == wspip) {
+ wspip->dma = dmaStreamAllocI(STM32_WSPI_OCTOSPI2_DMA_STREAM,
+ STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)wspi_lld_serve_dma_interrupt,
+ (void *)wspip);
+ osalDbgAssert(wspip->dma != NULL, "unable to allocate stream");
+ rccEnableOCTOSPI2(true);
+ dmaSetRequestSource(wspip->dma, STM32_DMAMUX1_OCTOSPI2);
+ }
+#endif
+
+ /* Common initializations.*/
+ dmaStreamSetPeripheral(wspip->dma, &wspip->ospi->DR);
+ }
+
+ /* WSPI setup and enable.*/
+ wspip->ospi->DCR1 = wspip->config->dcr1;
+ wspip->ospi->DCR2 = wspip->config->dcr2 |
+ STM32_DCR2_PRESCALER(STM32_WSPI_OCTOSPI1_PRESCALER_VALUE - 1U);
+ wspip->ospi->DCR3 = wspip->config->dcr3;
+ wspip->ospi->CR = OCTOSPI_CR_TCIE | OCTOSPI_CR_DMAEN | OCTOSPI_CR_EN;
+ wspip->ospi->FCR = OCTOSPI_FCR_CTEF | OCTOSPI_FCR_CTCF |
+ OCTOSPI_FCR_CSMF | OCTOSPI_FCR_CTOF;
+}
+
+/**
+ * @brief Deactivates the WSPI peripheral.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_stop(WSPIDriver *wspip) {
+
+ /* Waiting for the previous operation to complete, if any.*/
+ wspi_lld_sync(wspip);
+
+ /* If in ready state then disables the OCTOSPI clock.*/
+ if (wspip->state == WSPI_READY) {
+
+ /* WSPI disable.*/
+ wspip->ospi->CR = 0U;
+
+ /* Releasing the DMA.*/
+ dmaStreamFreeI(wspip->dma);
+ wspip->dma = NULL;
+
+ /* Stopping involved clocks.*/
+#if STM32_WSPI_USE_OCTOSPI1
+ if (&WSPID1 == wspip) {
+ rccDisableOCTOSPI1();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Sends a command without data phase.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ *
+ * @notapi
+ */
+void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp) {
+
+#if 0 //STM32_USE_STM32_D1_WORKAROUND == TRUE
+ /* If it is a command without address and alternate phases then the command
+ is sent as an alternate byte, the command phase is suppressed.*/
+ if ((cmdp->cfg & (WSPI_CFG_ADDR_MODE_MASK | WSPI_CFG_ALT_MODE_MASK)) == 0U) {
+ /* The command mode field is copied in the alternate mode field. All
+ other fields are not used in this scenario.*/
+ wspip->ospi->DLR = 0U;
+ wspip->ospi->ABR = cmdp->cmd;
+ wspip->ospi->CCR = (cmdp->cfg & WSPI_CFG_CMD_MODE_MASK) << 6U;
+ return;
+ }
+#endif
+ wspip->ospi->CR &= ~OCTOSPI_CR_FMODE;
+ wspip->ospi->DLR = 0U;
+ wspip->ospi->TCR = cmdp->dummy;
+ wspip->ospi->CCR = cmdp->cfg;
+ wspip->ospi->ABR = cmdp->alt;
+ wspip->ospi->IR = cmdp->cmd;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->ospi->AR = cmdp->addr;
+ }
+
+ /* Waiting for the previous operation to complete.*/
+ wspi_lld_sync(wspip);
+}
+
+/**
+ * @brief Sends a command with data over the WSPI bus.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note If using DTR in 8 lines mode then the following restrictions
+ * apply:
+ * - Command size must be 0, 2 or 4 bytes.
+ * - Address must be even.
+ * - Alternate bytes size must be 0, 2 or 4 bytes.
+ * - Data size must be a multiple of two.
+ * .
+ * There is no check on the above conditions in order to keep the
+ * code efficient.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[in] n number of bytes to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, const uint8_t *txbuf) {
+
+ dmaStreamSetMemory0(wspip->dma, txbuf);
+ dmaStreamSetTransactionSize(wspip->dma, n);
+ dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_M2P);
+
+ wspip->ospi->CR &= ~OCTOSPI_CR_FMODE;
+ wspip->ospi->DLR = n - 1U;
+ wspip->ospi->TCR = cmdp->dummy;
+ wspip->ospi->CCR = cmdp->cfg;
+ wspip->ospi->ABR = cmdp->alt;
+ wspip->ospi->IR = cmdp->cmd;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->ospi->AR = cmdp->addr;
+ }
+
+ dmaStreamEnable(wspip->dma);
+}
+
+/**
+ * @brief Sends a command then receives data over the WSPI bus.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note If using DTR in 8 lines mode then the following restrictions
+ * apply:
+ * - Command size must be 0, 2 or 4 bytes.
+ * - Address must be even.
+ * - Alternate bytes size must be 0, 2 or 4 bytes.
+ * - Data size must be a multiple of two.
+ * .
+ * There is no check on the above conditions in order to keep the
+ * code efficient.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[in] n number of bytes to send
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, uint8_t *rxbuf) {
+
+ dmaStreamSetMemory0(wspip->dma, rxbuf);
+ dmaStreamSetTransactionSize(wspip->dma, n);
+ dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_P2M);
+
+ wspip->ospi->CR = (wspip->ospi->CR & ~OCTOSPI_CR_FMODE) | OCTOSPI_CR_FMODE_0;
+ wspip->ospi->DLR = n - 1U;
+ wspip->ospi->TCR = cmdp->dummy;
+ wspip->ospi->CCR = cmdp->cfg;
+ wspip->ospi->ABR = cmdp->alt;
+ wspip->ospi->IR = cmdp->cmd;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->ospi->AR = cmdp->addr;
+ }
+
+ dmaStreamEnable(wspip->dma);
+}
+
+#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Maps in memory space a WSPI flash device.
+ * @pre The memory flash device must be initialized appropriately
+ * before mapping it in memory space.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[out] addrp pointer to the memory start address of the mapped
+ * flash or @p NULL
+ *
+ * @notapi
+ */
+void wspi_lld_map_flash(WSPIDriver *wspip,
+ const wspi_command_t *cmdp,
+ uint8_t **addrp) {
+
+ /* Starting memory mapped mode using the passed parameters.*/
+ wspip->ospi->CR = OCTOSPI_CR_FMODE_1 | OCTOSPI_CR_FMODE_0 | OCTOSPI_CR_EN;
+ wspip->ospi->TCR = cmdp->dummy;
+ wspip->ospi->CCR = cmdp->cfg;
+ wspip->ospi->IR = cmdp->cmd;
+ wspip->ospi->ABR = 0U;
+ wspip->ospi->AR = 0U;
+ wspip->ospi->WTCR = 0U;
+ wspip->ospi->WCCR = 0U;
+ wspip->ospi->WIR = 0U;
+ wspip->ospi->WABR = 0U;
+
+ /* Mapped flash absolute base address.*/
+#if STM32_WSPI_USE_OCTOSPI1
+ if (&WSPID1 == wspip) {
+ if (addrp != NULL) {
+ *addrp = (uint8_t *)0x90000000U;
+ }
+ }
+#endif
+#if STM32_WSPI_USE_OCTOSPI2
+ if (&WSPID2 == wspip) {
+ if (addrp != NULL) {
+ *addrp = (uint8_t *)0x70000000U;
+ }
+ }
+#endif
+}
+
+/**
+ * @brief Unmaps from memory space a WSPI flash device.
+ * @post The memory flash device must be re-initialized for normal
+ * commands exchange.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_unmap_flash(WSPIDriver *wspip) {
+
+ /* Aborting memory mapped mode.*/
+ wspip->ospi->CR |= OCTOSPI_CR_ABORT;
+ while ((wspip->ospi->CR & OCTOSPI_CR_ABORT) != 0U) {
+ }
+
+ /* Disabling memory mapped mode and re-enabling DMA and IRQs.*/
+ wspip->ospi->CR = OCTOSPI_CR_TCIE | OCTOSPI_CR_DMAEN | OCTOSPI_CR_EN;
+}
+#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */
+
+#endif /* HAL_USE_WSPI */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h new file mode 100644 index 0000000..35e5d80 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OCTOSPIv1/hal_wspi_lld.h @@ -0,0 +1,334 @@ +/*
+ 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 OCTOSPIv1/hal_wspi_lld.h
+ * @brief STM32 WSPI subsystem low level driver header.
+ *
+ * @addtogroup WSPI
+ * @{
+ */
+
+#ifndef HAL_WSPI_LLD_H
+#define HAL_WSPI_LLD_H
+
+#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name WSPI implementation capabilities
+ * @{
+ */
+#define WSPI_SUPPORTS_MEMMAP TRUE
+#define WSPI_DEFAULT_CFG_MASKS TRUE
+/** @} */
+
+/**
+ * @name DCR1 register options
+ * @{
+ */
+#define STM32_DCR1_CK_MODE (1U << 0U)
+#define STM32_DCR1_FRCK_MODE (1U << 1U)
+#define STM32_DCR1_CSHT_MASK (7U << 8U)
+#define STM32_DCR1_CSHT(n) ((n) << 8U)
+#define STM32_DCR1_DEVSIZE_MASK (31U << 16U)
+#define STM32_DCR1_DEVSIZE(n) ((n) << 16U)
+#define STM32_DCR1_MTYP_MASK (7U << 16U)
+#define STM32_DCR1_MTYP(n) ((n) << 24U)
+/** @} */
+
+/**
+ * @name DCR2 register options
+ * @{
+ */
+#define STM32_DCR2_PRESCALER_MASK (255U << 0U)
+#define STM32_DCR2_PRESCALER(n) ((n) << 0U)
+#define STM32_DCR2_WRAPSIZE_MASK (7U << 16U)
+#define STM32_DCR2_WRAPSIZE(n) ((n) << 16U)
+
+/**
+ * @name DCR3 register options
+ * @{
+ */
+#define STM32_DCR3_MAXTRAN_MASK (255U << 0U)
+#define STM32_DCR3_MAXTRAN(n) ((n) << 0U)
+#define STM32_DCR3_CSBOUND_MASK (7U << 16U)
+#define STM32_DCR3_CSBOUND(n) ((n) << 16U)
+
+/**
+ * @name DCR4 register options
+ * @{
+ */
+#define STM32_DCR4_REFRESH_MASK (255U << 0U)
+#define STM32_DCR4_REFRESH(n) ((n) << 0U)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief WSPID1 driver enable switch.
+ * @details If set to @p TRUE the support for OCTOSPI1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_WSPI_USE_OCTOSPI1) || defined(__DOXYGEN__)
+#define STM32_WSPI_USE_OCTOSPI1 FALSE
+#endif
+
+/**
+ * @brief WSPID2 driver enable switch.
+ * @details If set to @p TRUE the support for OCTOSPI2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_WSPI_USE_OCTOSPI2) || defined(__DOXYGEN__)
+#define STM32_WSPI_USE_OCTOSPI2 FALSE
+#endif
+
+/**
+ * @brief OCTOSPI1 prescaler setting.
+ * @note This is the prescaler divider value 1..256. The maximum frequency
+ * varies depending on the STM32 model and operating conditions,
+ * find the details in the data sheet.
+ */
+#if !defined(STM32_WSPI_OCTOSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI1_PRESCALER_VALUE 1
+#endif
+
+/**
+ * @brief OCTOSPI2 prescaler setting.
+ * @note This is the prescaler divider value 1..256. The maximum frequency
+ * varies depending on the STM32 model and operating conditions,
+ * find the details in the data sheet.
+ */
+#if !defined(STM32_WSPI_OCTOSPI2_PRESCALER_VALUE) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI2_PRESCALER_VALUE 1
+#endif
+
+/**
+ * @brief OCTOSPI1 interrupt priority level setting.
+ */
+#if !defined(STM32_WSPI_OCTOSPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief OCTOSPI2 interrupt priority level setting.
+ */
+#if !defined(STM32_WSPI_OCTOSPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief OCTOSPI1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_WSPI_OCTOSPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief OCTOSPI2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_WSPI_OCTOSPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief OCTOSPI1 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief OCTOSPI2 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief OCTOSPI DMA error hook.
+ */
+#if !defined(STM32_WSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_WSPI_DMA_ERROR_HOOK(qspip) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_OCTOSPI1)
+#define STM32_HAS_OCTOSPI1 FALSE
+#endif
+
+#if !defined(STM32_HAS_OCTOSPI2)
+#define STM32_HAS_OCTOSPI2 FALSE
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI1 && !STM32_HAS_OCTOSPI1
+#error "OCTOSPI1 not present in the selected device"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2 && !STM32_HAS_OCTOSPI2
+#error "OCTOSPI2 not present in the selected device"
+#endif
+
+#if !STM32_WSPI_USE_OCTOSPI1 && !STM32_WSPI_USE_OCTOSPI2
+#error "WSPI driver activated but no OCTOSPI peripheral assigned"
+#endif
+
+/* Check on OCTOSPI prescaler setting.*/
+#if (STM32_WSPI_OCTOSPI1_PRESCALER_VALUE < 1) || \
+ (STM32_WSPI_OCTOSPI1_PRESCALER_VALUE > 256)
+#error "STM32_WSPI_OCTOSPI1_PRESCALER_VALUE not within 1..256"
+#endif
+
+/* Check on IRQ priorities.*/
+#if STM32_WSPI_USE_OCTOSPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to OCTOSPI1"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to OCTOSPI2"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI1_DMA_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to OCTOSPI1 DMA"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI2_DMA_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to OCTOSPI2 DMA"
+#endif
+
+/* Check on the presence of the DMA channels settings in mcuconf.h.*/
+#if STM32_WSPI_USE_OCTOSPI1 && !defined(STM32_WSPI_OCTOSPI1_DMA_STREAM)
+#error "OCTOSPI1 DMA stream not defined"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2 && !defined(STM32_WSPI_OCTOSPI2_DMA_STREAM)
+#error "OCTOSPI2 DMA stream not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_WSPI_USE_OCTOSPI1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_WSPI_OCTOSPI1_DMA_STREAM)
+#error "invalid DMA stream associated to OCTOSPI1"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_WSPI_OCTOSPI2_DMA_STREAM)
+#error "invalid DMA stream associated to OCTOSPI2"
+#endif
+
+/* Check on DMA channels priority.*/
+#if STM32_WSPI_USE_OCTOSPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to OCTOSPI1"
+#endif
+
+#if STM32_WSPI_USE_OCTOSPI2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_WSPI_OCTOSPI2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to OCTOSPI2"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the WSPI configuration structure.
+ */
+#define wspi_lld_config_fields \
+ /* DCR1 register initialization data.*/ \
+ uint32_t dcr1; \
+ /* DCR2 register initialization data. The prescaler field is internally \
+ ORed to this field, leave it to zero.*/ \
+ uint32_t dcr2; \
+ /* DCR3 register initialization data.*/ \
+ uint32_t dcr3; \
+ /* DCR4 register initialization data.*/ \
+ uint32_t dcr4
+
+/**
+ * @brief Low level fields of the WSPI driver structure.
+ */
+#define wspi_lld_driver_fields \
+ /* Pointer to the OCTOSPIx registers block.*/ \
+ OCTOSPI_TypeDef *ospi; \
+ /* OCTOSPI DMA stream.*/ \
+ const stm32_dma_stream_t *dma; \
+ /* OCTOSPI DMA mode bit mask.*/ \
+ uint32_t dmamode
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if (STM32_WSPI_USE_OCTOSPI1 == TRUE) && !defined(__DOXYGEN__)
+extern WSPIDriver WSPID1;
+#endif
+
+#if (STM32_WSPI_USE_OCTOSPI2 == TRUE) && !defined(__DOXYGEN__)
+extern WSPIDriver WSPID2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void wspi_lld_init(void);
+ void wspi_lld_start(WSPIDriver *wspip);
+ void wspi_lld_stop(WSPIDriver *wspip);
+ void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp);
+ void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, const uint8_t *txbuf);
+ void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, uint8_t *rxbuf);
+#if WSPI_SUPPORTS_MEMMAP == TRUE
+ void wspi_lld_map_flash(WSPIDriver *wspip,
+ const wspi_command_t *cmdp,
+ uint8_t **addrp);
+ void wspi_lld_unmap_flash(WSPIDriver *wspip);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_WSPI */
+
+#endif /* HAL_WSPI_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk new file mode 100644 index 0000000..197c1d2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c new file mode 100644 index 0000000..0f48d1f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.c @@ -0,0 +1,1265 @@ +/*
+ 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 OTGv1/hal_usb_lld.c
+ * @brief STM32 USB subsystem low level driver source.
+ *
+ * @addtogroup USB
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if HAL_USE_USB || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define TRDT_VALUE_FS 5
+#define TRDT_VALUE_HS 9
+
+#define EP0_MAX_INSIZE 64
+#define EP0_MAX_OUTSIZE 64
+
+#if STM32_OTG_STEPPING == 1
+#if defined(BOARD_OTG_NOVBUSSENS)
+#define GCCFG_INIT_VALUE (GCCFG_NOVBUSSENS | GCCFG_VBUSASEN | \
+ GCCFG_VBUSBSEN | GCCFG_PWRDWN)
+#else
+#define GCCFG_INIT_VALUE (GCCFG_VBUSASEN | GCCFG_VBUSBSEN | \
+ GCCFG_PWRDWN)
+#endif
+
+#elif STM32_OTG_STEPPING == 2
+#if defined(BOARD_OTG_NOVBUSSENS)
+#define GCCFG_INIT_VALUE GCCFG_PWRDWN
+#else
+#define GCCFG_INIT_VALUE (GCCFG_VBDEN | GCCFG_PWRDWN)
+#endif
+
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief OTG_FS driver identifier.*/
+#if STM32_USB_USE_OTG1 || defined(__DOXYGEN__)
+USBDriver USBD1;
+#endif
+
+/** @brief OTG_HS driver identifier.*/
+#if STM32_USB_USE_OTG2 || defined(__DOXYGEN__)
+USBDriver USBD2;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief EP0 state.
+ * @note It is an union because IN and OUT endpoints are never used at the
+ * same time for EP0.
+ */
+static union {
+ /**
+ * @brief IN EP0 state.
+ */
+ USBInEndpointState in;
+ /**
+ * @brief OUT EP0 state.
+ */
+ USBOutEndpointState out;
+} ep0_state;
+
+/**
+ * @brief Buffer for the EP0 setup packets.
+ */
+static uint8_t ep0setup_buffer[8];
+
+/**
+ * @brief EP0 initialization structure.
+ */
+static const USBEndpointConfig ep0config = {
+ USB_EP_MODE_TYPE_CTRL,
+ _usb_ep0setup,
+ _usb_ep0in,
+ _usb_ep0out,
+ 0x40,
+ 0x40,
+ &ep0_state.in,
+ &ep0_state.out,
+ 1,
+ ep0setup_buffer
+};
+
+#if STM32_USB_USE_OTG1
+static const stm32_otg_params_t fsparams = {
+ STM32_USB_OTG1_RX_FIFO_SIZE / 4,
+ STM32_OTG1_FIFO_MEM_SIZE,
+ STM32_OTG1_ENDPOINTS
+};
+#endif
+
+#if STM32_USB_USE_OTG2
+static const stm32_otg_params_t hsparams = {
+ STM32_USB_OTG2_RX_FIFO_SIZE / 4,
+ STM32_OTG2_FIFO_MEM_SIZE,
+ STM32_OTG2_ENDPOINTS
+};
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static void otg_core_reset(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+
+ /* Wait AHB idle condition.*/
+ while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0)
+ ;
+
+ /* Core reset and delay of at least 3 PHY cycles.*/
+ otgp->GRSTCTL = GRSTCTL_CSRST;
+ osalSysPolledDelayX(12);
+ while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0)
+ ;
+
+ osalSysPolledDelayX(18);
+
+ /* Wait AHB idle condition again.*/
+ while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0)
+ ;
+}
+
+static void otg_disable_ep(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+ unsigned i;
+
+ for (i = 0; i <= usbp->otgparams->num_endpoints; i++) {
+
+ if ((otgp->ie[i].DIEPCTL & DIEPCTL_EPENA) != 0U) {
+ otgp->ie[i].DIEPCTL |= DIEPCTL_EPDIS;
+ }
+
+ if ((otgp->oe[i].DOEPCTL & DIEPCTL_EPENA) != 0U) {
+ otgp->oe[i].DOEPCTL |= DIEPCTL_EPDIS;
+ }
+
+ otgp->ie[i].DIEPINT = 0xFFFFFFFF;
+ otgp->oe[i].DOEPINT = 0xFFFFFFFF;
+ }
+ otgp->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0);
+}
+
+static void otg_rxfifo_flush(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+
+ otgp->GRSTCTL = GRSTCTL_RXFFLSH;
+ while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0)
+ ;
+ /* Wait for 3 PHY Clocks.*/
+ osalSysPolledDelayX(18);
+}
+
+static void otg_txfifo_flush(USBDriver *usbp, uint32_t fifo) {
+ stm32_otg_t *otgp = usbp->otg;
+
+ otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH;
+ while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0)
+ ;
+ /* Wait for 3 PHY Clocks.*/
+ osalSysPolledDelayX(18);
+}
+
+/**
+ * @brief Resets the FIFO RAM memory allocator.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+static void otg_ram_reset(USBDriver *usbp) {
+
+ usbp->pmnext = usbp->otgparams->rx_fifo_size;
+}
+
+/**
+ * @brief Allocates a block from the FIFO RAM memory.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] size size of the packet buffer to allocate in words
+ *
+ * @notapi
+ */
+static uint32_t otg_ram_alloc(USBDriver *usbp, size_t size) {
+ uint32_t next;
+
+ next = usbp->pmnext;
+ usbp->pmnext += size;
+ osalDbgAssert(usbp->pmnext <= usbp->otgparams->otg_ram_size,
+ "OTG FIFO memory overflow");
+ return next;
+}
+
+/**
+ * @brief Writes to a TX FIFO.
+ *
+ * @param[in] fifop pointer to the FIFO register
+ * @param[in] buf buffer where to copy the endpoint data
+ * @param[in] n maximum number of bytes to copy
+ *
+ * @notapi
+ */
+static void otg_fifo_write_from_buffer(volatile uint32_t *fifop,
+ const uint8_t *buf,
+ size_t n) {
+
+ osalDbgAssert(n > 0, "is zero");
+
+ while (true) {
+ *fifop = *((uint32_t *)buf);
+ if (n <= 4) {
+ break;
+ }
+ n -= 4;
+ buf += 4;
+ }
+}
+
+/**
+ * @brief Reads a packet from the RXFIFO.
+ *
+ * @param[in] fifop pointer to the FIFO register
+ * @param[out] buf buffer where to copy the endpoint data
+ * @param[in] n number of bytes to pull from the FIFO
+ * @param[in] max number of bytes to copy into the buffer
+ *
+ * @notapi
+ */
+static void otg_fifo_read_to_buffer(volatile uint32_t *fifop,
+ uint8_t *buf,
+ size_t n,
+ size_t max) {
+ uint32_t w = 0;
+ size_t i = 0;
+
+ while (i < n) {
+ if ((i & 3) == 0) {
+ w = *fifop;
+ }
+ if (i < max) {
+ *buf++ = (uint8_t)w;
+ w >>= 8;
+ }
+ i++;
+ }
+}
+
+/**
+ * @brief Incoming packets handler.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+static void otg_rxfifo_handler(USBDriver *usbp) {
+ uint32_t sts, cnt, ep;
+
+ /* Popping the event word out of the RX FIFO.*/
+ sts = usbp->otg->GRXSTSP;
+
+ /* Event details.*/
+ cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF;
+ ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF;
+
+ switch (sts & GRXSTSP_PKTSTS_MASK) {
+ case GRXSTSP_SETUP_DATA:
+ otg_fifo_read_to_buffer(usbp->otg->FIFO[0], usbp->epc[ep]->setup_buf,
+ cnt, 8);
+ break;
+ case GRXSTSP_SETUP_COMP:
+ break;
+ case GRXSTSP_OUT_DATA:
+ otg_fifo_read_to_buffer(usbp->otg->FIFO[0],
+ usbp->epc[ep]->out_state->rxbuf,
+ cnt,
+ usbp->epc[ep]->out_state->rxsize -
+ usbp->epc[ep]->out_state->rxcnt);
+ usbp->epc[ep]->out_state->rxbuf += cnt;
+ usbp->epc[ep]->out_state->rxcnt += cnt;
+ break;
+ case GRXSTSP_OUT_COMP:
+ break;
+ case GRXSTSP_OUT_GLOBAL_NAK:
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief Outgoing packets handler.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+static bool otg_txfifo_handler(USBDriver *usbp, usbep_t ep) {
+
+ /* The TXFIFO is filled until there is space and data to be transmitted.*/
+ while (true) {
+ uint32_t n;
+
+ /* Transaction end condition.*/
+ if (usbp->epc[ep]->in_state->txcnt >= usbp->epc[ep]->in_state->txsize) {
+#if 1
+ usbp->otg->DIEPEMPMSK &= ~DIEPEMPMSK_INEPTXFEM(ep);
+#endif
+ return true;
+ }
+
+ /* Number of bytes remaining in current transaction.*/
+ n = usbp->epc[ep]->in_state->txsize - usbp->epc[ep]->in_state->txcnt;
+ if (n > usbp->epc[ep]->in_maxsize)
+ n = usbp->epc[ep]->in_maxsize;
+
+ /* Checks if in the TXFIFO there is enough space to accommodate the
+ next packet.*/
+ if (((usbp->otg->ie[ep].DTXFSTS & DTXFSTS_INEPTFSAV_MASK) * 4) < n)
+ return false;
+
+#if STM32_USB_OTGFIFO_FILL_BASEPRI
+ __set_BASEPRI(CORTEX_PRIO_MASK(STM32_USB_OTGFIFO_FILL_BASEPRI));
+#endif
+ otg_fifo_write_from_buffer(usbp->otg->FIFO[ep],
+ usbp->epc[ep]->in_state->txbuf,
+ n);
+ usbp->epc[ep]->in_state->txbuf += n;
+ usbp->epc[ep]->in_state->txcnt += n;
+#if STM32_USB_OTGFIFO_FILL_BASEPRI
+ __set_BASEPRI(0);
+#endif
+ }
+}
+
+/**
+ * @brief Generic endpoint IN handler.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+static void otg_epin_handler(USBDriver *usbp, usbep_t ep) {
+ stm32_otg_t *otgp = usbp->otg;
+ uint32_t epint = otgp->ie[ep].DIEPINT;
+
+ otgp->ie[ep].DIEPINT = epint;
+
+ if (epint & DIEPINT_TOC) {
+ /* Timeouts not handled yet, not sure how to handle.*/
+ }
+ if ((epint & DIEPINT_XFRC) && (otgp->DIEPMSK & DIEPMSK_XFRCM)) {
+ /* Transmit transfer complete.*/
+ USBInEndpointState *isp = usbp->epc[ep]->in_state;
+
+ if (isp->txsize < isp->totsize) {
+ /* In case the transaction covered only part of the total transfer
+ then another transaction is immediately started in order to
+ cover the remaining.*/
+ isp->txsize = isp->totsize - isp->txsize;
+ isp->txcnt = 0;
+ osalSysLockFromISR();
+ usb_lld_start_in(usbp, ep);
+ osalSysUnlockFromISR();
+ }
+ else {
+ /* End on IN transfer.*/
+ _usb_isr_invoke_in_cb(usbp, ep);
+ }
+ }
+ if ((epint & DIEPINT_TXFE) &&
+ (otgp->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) {
+ /* TX FIFO empty or emptying.*/
+ otg_txfifo_handler(usbp, ep);
+ }
+}
+
+/**
+ * @brief Generic endpoint OUT handler.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+static void otg_epout_handler(USBDriver *usbp, usbep_t ep) {
+ stm32_otg_t *otgp = usbp->otg;
+ uint32_t epint = otgp->oe[ep].DOEPINT;
+
+ /* Resets all EP IRQ sources.*/
+ otgp->oe[ep].DOEPINT = epint;
+
+ if ((epint & DOEPINT_STUP) && (otgp->DOEPMSK & DOEPMSK_STUPM)) {
+ /* Setup packets handling, setup packets are handled using a
+ specific callback.*/
+ _usb_isr_invoke_setup_cb(usbp, ep);
+ }
+
+ if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) {
+ USBOutEndpointState *osp;
+
+ /* OUT state structure pointer for this endpoint.*/
+ osp = usbp->epc[ep]->out_state;
+
+ /* EP0 requires special handling.*/
+ if (ep == 0) {
+
+#if defined(STM32_OTG_SEQUENCE_WORKAROUND)
+ /* If an OUT transaction end interrupt is processed while the state
+ machine is not in an OUT state then it is ignored, this is caused
+ on some devices (L4) apparently injecting spurious data complete
+ words in the RX FIFO.*/
+ if ((usbp->ep0state & USB_OUT_STATE) == 0)
+ return;
+#endif
+
+ /* In case the transaction covered only part of the total transfer
+ then another transaction is immediately started in order to
+ cover the remaining.*/
+ if (((osp->rxcnt % usbp->epc[ep]->out_maxsize) == 0) &&
+ (osp->rxsize < osp->totsize)) {
+ osp->rxsize = osp->totsize - osp->rxsize;
+ osp->rxcnt = 0;
+ osalSysLockFromISR();
+ usb_lld_start_out(usbp, ep);
+ osalSysUnlockFromISR();
+ return;
+ }
+ }
+
+ /* End on OUT transfer.*/
+ _usb_isr_invoke_out_cb(usbp, ep);
+ }
+}
+
+/**
+ * @brief Isochronous IN transfer failed handler.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+static void otg_isoc_in_failed_handler(USBDriver *usbp) {
+ usbep_t ep;
+ stm32_otg_t *otgp = usbp->otg;
+
+ for (ep = 0; ep <= usbp->otgparams->num_endpoints; ep++) {
+ if (((otgp->ie[ep].DIEPCTL & DIEPCTL_EPTYP_MASK) == DIEPCTL_EPTYP_ISO) &&
+ ((otgp->ie[ep].DIEPCTL & DIEPCTL_EPENA) != 0)) {
+ /* Endpoint enabled -> ISOC IN transfer failed */
+ /* Disable endpoint */
+ otgp->ie[ep].DIEPCTL |= (DIEPCTL_EPDIS | DIEPCTL_SNAK);
+ while (otgp->ie[ep].DIEPCTL & DIEPCTL_EPENA)
+ ;
+
+ /* Flush FIFO */
+ otg_txfifo_flush(usbp, ep);
+
+ /* Prepare data for next frame */
+ _usb_isr_invoke_in_cb(usbp, ep);
+
+ /* TX FIFO empty or emptying.*/
+ otg_txfifo_handler(usbp, ep);
+ }
+ }
+}
+
+/**
+ * @brief Isochronous OUT transfer failed handler.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+static void otg_isoc_out_failed_handler(USBDriver *usbp) {
+ usbep_t ep;
+ stm32_otg_t *otgp = usbp->otg;
+
+ for (ep = 0; ep <= usbp->otgparams->num_endpoints; ep++) {
+ if (((otgp->oe[ep].DOEPCTL & DOEPCTL_EPTYP_MASK) == DOEPCTL_EPTYP_ISO) &&
+ ((otgp->oe[ep].DOEPCTL & DOEPCTL_EPENA) != 0)) {
+ /* Endpoint enabled -> ISOC OUT transfer failed */
+ /* Disable endpoint */
+ /* CHTODO:: Core stucks here */
+ /*otgp->oe[ep].DOEPCTL |= (DOEPCTL_EPDIS | DOEPCTL_SNAK);
+ while (otgp->oe[ep].DOEPCTL & DOEPCTL_EPENA)
+ ;*/
+ /* Prepare transfer for next frame.*/
+ _usb_isr_invoke_out_cb(usbp, ep);
+ }
+ }
+}
+
+/**
+ * @brief OTG shared ISR.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+static void usb_lld_serve_interrupt(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+ uint32_t sts, src;
+
+ sts = otgp->GINTSTS;
+ sts &= otgp->GINTMSK;
+ otgp->GINTSTS = sts;
+
+ /* Reset interrupt handling.*/
+ if (sts & GINTSTS_USBRST) {
+ /* Default reset action.*/
+ _usb_reset(usbp);
+
+ /* Preventing execution of more handlers, the core has been reset.*/
+ return;
+ }
+
+ /* Wake-up handling.*/
+ if (sts & GINTSTS_WKUPINT) {
+ /* If clocks are gated off, turn them back on (may be the case if
+ coming out of suspend mode).*/
+ if (otgp->PCGCCTL & (PCGCCTL_STPPCLK | PCGCCTL_GATEHCLK)) {
+ /* Set to zero to un-gate the USB core clocks.*/
+ otgp->PCGCCTL &= ~(PCGCCTL_STPPCLK | PCGCCTL_GATEHCLK);
+ }
+
+ /* Clear the Remote Wake-up Signaling.*/
+ otgp->DCTL &= ~DCTL_RWUSIG;
+
+ _usb_wakeup(usbp);
+ }
+
+ /* Suspend handling.*/
+ if (sts & GINTSTS_USBSUSP) {
+ /* Stopping all ongoing transfers.*/
+ otg_disable_ep(usbp);
+
+ /* Default suspend action.*/
+ _usb_suspend(usbp);
+ }
+
+ /* Enumeration done.*/
+ if (sts & GINTSTS_ENUMDNE) {
+ /* Full or High speed timing selection.*/
+ if ((otgp->DSTS & DSTS_ENUMSPD_MASK) == DSTS_ENUMSPD_HS_480) {
+ otgp->GUSBCFG = (otgp->GUSBCFG & ~(GUSBCFG_TRDT_MASK)) |
+ GUSBCFG_TRDT(TRDT_VALUE_HS);
+ }
+ else {
+ otgp->GUSBCFG = (otgp->GUSBCFG & ~(GUSBCFG_TRDT_MASK)) |
+ GUSBCFG_TRDT(TRDT_VALUE_FS);
+ }
+ }
+
+ /* SOF interrupt handling.*/
+ if (sts & GINTSTS_SOF) {
+ _usb_isr_invoke_sof_cb(usbp);
+ }
+
+ /* Isochronous IN failed handling */
+ if (sts & GINTSTS_IISOIXFR) {
+ otg_isoc_in_failed_handler(usbp);
+ }
+
+ /* Isochronous OUT failed handling */
+ if (sts & GINTSTS_IISOOXFR) {
+ otg_isoc_out_failed_handler(usbp);
+ }
+
+ /* Performing the whole FIFO emptying in the ISR, it is advised to keep
+ this IRQ at a very low priority level.*/
+ if ((sts & GINTSTS_RXFLVL) != 0U) {
+ otg_rxfifo_handler(usbp);
+ }
+
+ /* IN/OUT endpoints event handling.*/
+ src = otgp->DAINT;
+ if (sts & GINTSTS_OEPINT) {
+ if (src & (1 << 16))
+ otg_epout_handler(usbp, 0);
+ if (src & (1 << 17))
+ otg_epout_handler(usbp, 1);
+ if (src & (1 << 18))
+ otg_epout_handler(usbp, 2);
+ if (src & (1 << 19))
+ otg_epout_handler(usbp, 3);
+#if USB_MAX_ENDPOINTS >= 4
+ if (src & (1 << 20))
+ otg_epout_handler(usbp, 4);
+#endif
+#if USB_MAX_ENDPOINTS >= 5
+ if (src & (1 << 21))
+ otg_epout_handler(usbp, 5);
+#endif
+#if USB_MAX_ENDPOINTS >= 6
+ if (src & (1 << 22))
+ otg_epout_handler(usbp, 6);
+#endif
+#if USB_MAX_ENDPOINTS >= 7
+ if (src & (1 << 23))
+ otg_epout_handler(usbp, 7);
+#endif
+#if USB_MAX_ENDPOINTS >= 8
+ if (src & (1 << 24))
+ otg_epout_handler(usbp, 8);
+#endif
+ }
+ if (sts & GINTSTS_IEPINT) {
+ if (src & (1 << 0))
+ otg_epin_handler(usbp, 0);
+ if (src & (1 << 1))
+ otg_epin_handler(usbp, 1);
+ if (src & (1 << 2))
+ otg_epin_handler(usbp, 2);
+ if (src & (1 << 3))
+ otg_epin_handler(usbp, 3);
+#if USB_MAX_ENDPOINTS >= 4
+ if (src & (1 << 4))
+ otg_epin_handler(usbp, 4);
+#endif
+#if USB_MAX_ENDPOINTS >= 5
+ if (src & (1 << 5))
+ otg_epin_handler(usbp, 5);
+#endif
+#if USB_MAX_ENDPOINTS >= 6
+ if (src & (1 << 6))
+ otg_epin_handler(usbp, 6);
+#endif
+#if USB_MAX_ENDPOINTS >= 7
+ if (src & (1 << 7))
+ otg_epin_handler(usbp, 7);
+#endif
+#if USB_MAX_ENDPOINTS >= 8
+ if (src & (1 << 8))
+ otg_epin_handler(usbp, 8);
+#endif
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_USB_USE_OTG1 || defined(__DOXYGEN__)
+/**
+ * @brief OTG1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_OTG1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ usb_lld_serve_interrupt(&USBD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_USB_USE_OTG2 || defined(__DOXYGEN__)
+/**
+ * @brief OTG2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_OTG2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ usb_lld_serve_interrupt(&USBD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level USB driver initialization.
+ *
+ * @notapi
+ */
+void usb_lld_init(void) {
+
+ /* Driver initialization.*/
+#if STM32_USB_USE_OTG1
+ usbObjectInit(&USBD1);
+ USBD1.otg = OTG_FS;
+ USBD1.otgparams = &fsparams;
+
+#endif
+
+#if STM32_USB_USE_OTG2
+ usbObjectInit(&USBD2);
+ USBD2.otg = OTG_HS;
+ USBD2.otgparams = &hsparams;
+#endif
+}
+
+/**
+ * @brief Configures and activates the USB peripheral.
+ * @note Starting the OTG cell can be a slow operation carried out with
+ * interrupts disabled, perform it before starting time-critical
+ * operations.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_start(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+
+ if (usbp->state == USB_STOP) {
+ /* Clock activation.*/
+
+#if STM32_USB_USE_OTG1
+ if (&USBD1 == usbp) {
+ /* OTG FS clock enable and reset.*/
+ rccEnableOTG_FS(true);
+ rccResetOTG_FS();
+
+ /* Enables IRQ vector.*/
+ nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY);
+
+ /* - Forced device mode.
+ - USB turn-around time = TRDT_VALUE_FS.
+ - Full Speed 1.1 PHY.*/
+ otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE_FS) |
+ GUSBCFG_PHYSEL;
+
+ /* 48MHz 1.1 PHY.*/
+ otgp->DCFG = 0x02200000 | DCFG_DSPD_FS11;
+ }
+#endif
+
+#if STM32_USB_USE_OTG2
+ if (&USBD2 == usbp) {
+ /* OTG HS clock enable and reset.*/
+ rccEnableOTG_HS(true);
+ rccResetOTG_HS();
+
+ /* ULPI clock is managed depending on the presence of an external
+ PHY.*/
+#if defined(BOARD_OTG2_USES_ULPI)
+ rccEnableOTG_HSULPI(true);
+#else
+ /* Workaround for the problem described here:
+ http://forum.chibios.org/phpbb/viewtopic.php?f=16&t=1798.*/
+ rccDisableOTG_HSULPI();
+#endif
+
+ /* Enables IRQ vector.*/
+ nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY);
+
+ /* - Forced device mode.
+ - USB turn-around time = TRDT_VALUE_HS or TRDT_VALUE_FS.*/
+#if defined(BOARD_OTG2_USES_ULPI)
+ /* High speed ULPI PHY.*/
+ otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE_HS) |
+ GUSBCFG_SRPCAP | GUSBCFG_HNPCAP;
+#else
+ otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE_FS) |
+ GUSBCFG_PHYSEL;
+#endif
+
+#if defined(BOARD_OTG2_USES_ULPI)
+#if STM32_USE_USB_OTG2_HS
+ /* USB 2.0 High Speed PHY in HS mode.*/
+ otgp->DCFG = 0x02200000 | DCFG_DSPD_HS;
+#else
+ /* USB 2.0 High Speed PHY in FS mode.*/
+ otgp->DCFG = 0x02200000 | DCFG_DSPD_HS_FS;
+#endif
+#else
+ /* 48MHz 1.1 PHY.*/
+ otgp->DCFG = 0x02200000 | DCFG_DSPD_FS11;
+#endif
+ }
+#endif
+
+ /* PHY enabled.*/
+ otgp->PCGCCTL = 0;
+
+ /* VBUS sensing and transceiver enabled.*/
+ otgp->GOTGCTL = GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL;
+
+#if defined(BOARD_OTG2_USES_ULPI)
+#if STM32_USB_USE_OTG1
+ if (&USBD1 == usbp) {
+ otgp->GCCFG = GCCFG_INIT_VALUE;
+ }
+#endif
+
+#if STM32_USB_USE_OTG2
+ if (&USBD2 == usbp) {
+ otgp->GCCFG = 0;
+ }
+#endif
+#else
+ otgp->GCCFG = GCCFG_INIT_VALUE;
+#endif
+
+ /* Soft core reset.*/
+ otg_core_reset(usbp);
+
+ /* Interrupts on TXFIFOs half empty.*/
+ otgp->GAHBCFG = 0;
+
+ /* Endpoints re-initialization.*/
+ otg_disable_ep(usbp);
+
+ /* Clear all pending Device Interrupts, only the USB Reset interrupt
+ is required initially.*/
+ otgp->DIEPMSK = 0;
+ otgp->DOEPMSK = 0;
+ otgp->DAINTMSK = 0;
+ if (usbp->config->sof_cb == NULL)
+ otgp->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM | GINTMSK_USBSUSPM |
+ GINTMSK_ESUSPM | GINTMSK_SRQM | GINTMSK_WKUM |
+ GINTMSK_IISOIXFRM | GINTMSK_IISOOXFRM;
+ else
+ otgp->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM | GINTMSK_USBSUSPM |
+ GINTMSK_ESUSPM | GINTMSK_SRQM | GINTMSK_WKUM |
+ GINTMSK_IISOIXFRM | GINTMSK_IISOOXFRM |
+ GINTMSK_SOFM;
+
+ /* Clears all pending IRQs, if any. */
+ otgp->GINTSTS = 0xFFFFFFFF;
+
+ /* Global interrupts enable.*/
+ otgp->GAHBCFG |= GAHBCFG_GINTMSK;
+ }
+}
+
+/**
+ * @brief Deactivates the USB peripheral.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_stop(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+
+ /* If in ready state then disables the USB clock.*/
+ if (usbp->state != USB_STOP) {
+
+ /* Disabling all endpoints in case the driver has been stopped while
+ active.*/
+ otg_disable_ep(usbp);
+
+ otgp->DAINTMSK = 0;
+ otgp->GAHBCFG = 0;
+ otgp->GCCFG = 0;
+
+#if STM32_USB_USE_OTG1
+ if (&USBD1 == usbp) {
+ nvicDisableVector(STM32_OTG1_NUMBER);
+ rccDisableOTG_FS();
+ }
+#endif
+
+#if STM32_USB_USE_OTG2
+ if (&USBD2 == usbp) {
+ nvicDisableVector(STM32_OTG2_NUMBER);
+ rccDisableOTG_HS();
+#if defined(BOARD_OTG2_USES_ULPI)
+ rccDisableOTG_HSULPI()
+#endif
+ }
+#endif
+ }
+}
+
+/**
+ * @brief USB low level reset routine.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_reset(USBDriver *usbp) {
+ unsigned i;
+ stm32_otg_t *otgp = usbp->otg;
+
+ /* Flush the Tx FIFO.*/
+ otg_txfifo_flush(usbp, 0);
+
+ /* Endpoint interrupts all disabled and cleared.*/
+ otgp->DIEPEMPMSK = 0;
+ otgp->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0);
+
+ /* All endpoints in NAK mode, interrupts cleared.*/
+ for (i = 0; i <= usbp->otgparams->num_endpoints; i++) {
+ otgp->ie[i].DIEPCTL = DIEPCTL_SNAK;
+ otgp->oe[i].DOEPCTL = DOEPCTL_SNAK;
+ otgp->ie[i].DIEPINT = 0xFFFFFFFF;
+ otgp->oe[i].DOEPINT = 0xFFFFFFFF;
+ }
+
+ /* Resets the FIFO memory allocator.*/
+ otg_ram_reset(usbp);
+
+ /* Receive FIFO size initialization, the address is always zero.*/
+ otgp->GRXFSIZ = usbp->otgparams->rx_fifo_size;
+ otg_rxfifo_flush(usbp);
+
+ /* Resets the device address to zero.*/
+ otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(0);
+
+ /* Enables also EP-related interrupt sources.*/
+ otgp->GINTMSK |= GINTMSK_RXFLVLM | GINTMSK_OEPM | GINTMSK_IEPM;
+ otgp->DIEPMSK = DIEPMSK_TOCM | DIEPMSK_XFRCM;
+ otgp->DOEPMSK = DOEPMSK_STUPM | DOEPMSK_XFRCM;
+
+ /* EP0 initialization, it is a special case.*/
+ usbp->epc[0] = &ep0config;
+ otgp->oe[0].DOEPTSIZ = DOEPTSIZ_STUPCNT(3);
+ otgp->oe[0].DOEPCTL = DOEPCTL_SD0PID | DOEPCTL_USBAEP | DOEPCTL_EPTYP_CTRL |
+ DOEPCTL_MPSIZ(ep0config.out_maxsize);
+ otgp->ie[0].DIEPTSIZ = 0;
+ otgp->ie[0].DIEPCTL = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL |
+ DIEPCTL_TXFNUM(0) | DIEPCTL_MPSIZ(ep0config.in_maxsize);
+ otgp->DIEPTXF0 = DIEPTXF_INEPTXFD(ep0config.in_maxsize / 4) |
+ DIEPTXF_INEPTXSA(otg_ram_alloc(usbp,
+ ep0config.in_maxsize / 4));
+}
+
+/**
+ * @brief Sets the USB address.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_set_address(USBDriver *usbp) {
+ stm32_otg_t *otgp = usbp->otg;
+
+ otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(usbp->address);
+}
+
+/**
+ * @brief Enables an endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
+ uint32_t ctl, fsize;
+ stm32_otg_t *otgp = usbp->otg;
+
+ /* IN and OUT common parameters.*/
+ switch (usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) {
+ case USB_EP_MODE_TYPE_CTRL:
+ ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL;
+ break;
+ case USB_EP_MODE_TYPE_ISOC:
+ ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_ISO;
+ break;
+ case USB_EP_MODE_TYPE_BULK:
+ ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_BULK;
+ break;
+ case USB_EP_MODE_TYPE_INTR:
+ ctl = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_INTR;
+ break;
+ default:
+ return;
+ }
+
+ /* OUT endpoint activation or deactivation.*/
+ otgp->oe[ep].DOEPTSIZ = 0;
+ if (usbp->epc[ep]->out_state != NULL) {
+ otgp->oe[ep].DOEPCTL = ctl | DOEPCTL_MPSIZ(usbp->epc[ep]->out_maxsize);
+ otgp->DAINTMSK |= DAINTMSK_OEPM(ep);
+ }
+ else {
+ otgp->oe[ep].DOEPCTL &= ~DOEPCTL_USBAEP;
+ otgp->DAINTMSK &= ~DAINTMSK_OEPM(ep);
+ }
+
+ /* IN endpoint activation or deactivation.*/
+ otgp->ie[ep].DIEPTSIZ = 0;
+ if (usbp->epc[ep]->in_state != NULL) {
+ /* FIFO allocation for the IN endpoint.*/
+ fsize = usbp->epc[ep]->in_maxsize / 4;
+ if (usbp->epc[ep]->in_multiplier > 1)
+ fsize *= usbp->epc[ep]->in_multiplier;
+ otgp->DIEPTXF[ep - 1] = DIEPTXF_INEPTXFD(fsize) |
+ DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, fsize));
+ otg_txfifo_flush(usbp, ep);
+
+ otgp->ie[ep].DIEPCTL = ctl |
+ DIEPCTL_TXFNUM(ep) |
+ DIEPCTL_MPSIZ(usbp->epc[ep]->in_maxsize);
+ otgp->DAINTMSK |= DAINTMSK_IEPM(ep);
+ }
+ else {
+ otgp->DIEPTXF[ep - 1] = 0x02000400; /* Reset value.*/
+ otg_txfifo_flush(usbp, ep);
+ otgp->ie[ep].DIEPCTL &= ~DIEPCTL_USBAEP;
+ otgp->DAINTMSK &= ~DAINTMSK_IEPM(ep);
+ }
+}
+
+/**
+ * @brief Disables all the active endpoints except the endpoint zero.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_disable_endpoints(USBDriver *usbp) {
+
+ /* Resets the FIFO memory allocator.*/
+ otg_ram_reset(usbp);
+
+ /* Disabling all endpoints.*/
+ otg_disable_ep(usbp);
+}
+
+/**
+ * @brief Returns the status of an OUT endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return The endpoint status.
+ * @retval EP_STATUS_DISABLED The endpoint is not active.
+ * @retval EP_STATUS_STALLED The endpoint is stalled.
+ * @retval EP_STATUS_ACTIVE The endpoint is active.
+ *
+ * @notapi
+ */
+usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
+ uint32_t ctl;
+
+ (void)usbp;
+
+ ctl = usbp->otg->oe[ep].DOEPCTL;
+ if (!(ctl & DOEPCTL_USBAEP))
+ return EP_STATUS_DISABLED;
+ if (ctl & DOEPCTL_STALL)
+ return EP_STATUS_STALLED;
+ return EP_STATUS_ACTIVE;
+}
+
+/**
+ * @brief Returns the status of an IN endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return The endpoint status.
+ * @retval EP_STATUS_DISABLED The endpoint is not active.
+ * @retval EP_STATUS_STALLED The endpoint is stalled.
+ * @retval EP_STATUS_ACTIVE The endpoint is active.
+ *
+ * @notapi
+ */
+usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
+ uint32_t ctl;
+
+ (void)usbp;
+
+ ctl = usbp->otg->ie[ep].DIEPCTL;
+ if (!(ctl & DIEPCTL_USBAEP))
+ return EP_STATUS_DISABLED;
+ if (ctl & DIEPCTL_STALL)
+ return EP_STATUS_STALLED;
+ return EP_STATUS_ACTIVE;
+}
+
+/**
+ * @brief Reads a setup packet from the dedicated packet buffer.
+ * @details This function must be invoked in the context of the @p setup_cb
+ * callback in order to read the received setup packet.
+ * @pre In order to use this function the endpoint must have been
+ * initialized as a control endpoint.
+ * @post The endpoint is ready to accept another packet.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @param[out] buf buffer where to copy the packet data
+ *
+ * @notapi
+ */
+void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
+
+ memcpy(buf, usbp->epc[ep]->setup_buf, 8);
+}
+
+/**
+ * @brief Starts a receive operation on an OUT endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
+ uint32_t pcnt, rxsize;
+ USBOutEndpointState *osp = usbp->epc[ep]->out_state;
+
+ /* Transfer initialization.*/
+ osp->totsize = osp->rxsize;
+ if ((ep == 0) && (osp->rxsize > EP0_MAX_OUTSIZE))
+ osp->rxsize = EP0_MAX_OUTSIZE;
+
+ /* Transaction size is rounded to a multiple of packet size because the
+ following requirement in the RM:
+ "For OUT transfers, the transfer size field in the endpoint's transfer
+ size register must be a multiple of the maximum packet size of the
+ endpoint, adjusted to the Word boundary".*/
+ pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1U) /
+ usbp->epc[ep]->out_maxsize;
+ rxsize = (pcnt * usbp->epc[ep]->out_maxsize + 3U) & 0xFFFFFFFCU;
+
+ /*Setting up transaction parameters in DOEPTSIZ.*/
+ usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) |
+ DOEPTSIZ_XFRSIZ(rxsize);
+
+ /* Special case of isochronous endpoint.*/
+ if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) {
+ /* Odd/even bit toggling for isochronous endpoint.*/
+ if (usbp->otg->DSTS & DSTS_FNSOF_ODD)
+ usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SEVNFRM;
+ else
+ usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SODDFRM;
+ }
+
+ /* Starting operation.*/
+ usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_EPENA | DOEPCTL_CNAK;
+}
+
+/**
+ * @brief Starts a transmit operation on an IN endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
+ USBInEndpointState *isp = usbp->epc[ep]->in_state;
+
+ /* Transfer initialization.*/
+ isp->totsize = isp->txsize;
+ if (isp->txsize == 0) {
+ /* Special case, sending zero size packet.*/
+ usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
+ }
+ else {
+ if ((ep == 0) && (isp->txsize > EP0_MAX_INSIZE))
+ isp->txsize = EP0_MAX_INSIZE;
+
+ /* Normal case.*/
+ uint32_t pcnt = (isp->txsize + usbp->epc[ep]->in_maxsize - 1) /
+ usbp->epc[ep]->in_maxsize;
+ /* CHTODO: Support more than one packet per frame for isochronous transfers.*/
+ usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_MCNT(1) | DIEPTSIZ_PKTCNT(pcnt) |
+ DIEPTSIZ_XFRSIZ(isp->txsize);
+ }
+
+ /* Special case of isochronous endpoint.*/
+ if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) {
+ /* Odd/even bit toggling.*/
+ if (usbp->otg->DSTS & DSTS_FNSOF_ODD)
+ usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_SEVNFRM;
+ else
+ usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_SODDFRM;
+ }
+
+ /* Starting operation.*/
+ usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK;
+ usbp->otg->DIEPEMPMSK |= DIEPEMPMSK_INEPTXFEM(ep);
+}
+
+/**
+ * @brief Brings an OUT endpoint in the stalled state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
+
+ usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_STALL;
+}
+
+/**
+ * @brief Brings an IN endpoint in the stalled state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
+
+ usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_STALL;
+}
+
+/**
+ * @brief Brings an OUT endpoint in the active state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
+
+ usbp->otg->oe[ep].DOEPCTL &= ~DOEPCTL_STALL;
+}
+
+/**
+ * @brief Brings an IN endpoint in the active state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
+
+ usbp->otg->ie[ep].DIEPCTL &= ~DIEPCTL_STALL;
+}
+
+#endif /* HAL_USE_USB */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h new file mode 100644 index 0000000..08add51 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/hal_usb_lld.h @@ -0,0 +1,610 @@ +/*
+ 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 OTGv1/hal_usb_lld.h
+ * @brief STM32 USB subsystem low level driver header.
+ *
+ * @addtogroup USB
+ * @{
+ */
+
+#ifndef HAL_USB_LLD_H
+#define HAL_USB_LLD_H
+
+#if HAL_USE_USB || defined(__DOXYGEN__)
+
+#include "stm32_otg.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Status stage handling method.
+ */
+#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_SW
+
+/**
+ * @brief The address can be changed immediately upon packet reception.
+ */
+#define USB_SET_ADDRESS_MODE USB_EARLY_SET_ADDRESS
+
+/**
+ * @brief Method for set address acknowledge.
+ */
+#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief OTG1 driver enable switch.
+ * @details If set to @p TRUE the support for OTG_FS is included.
+ * @note The default is @p FALSE
+ */
+#if !defined(STM32_USB_USE_OTG1) || defined(__DOXYGEN__)
+#define STM32_USB_USE_OTG1 FALSE
+#endif
+
+/**
+ * @brief OTG2 driver enable switch.
+ * @details If set to @p TRUE the support for OTG_HS is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_USB_USE_OTG2) || defined(__DOXYGEN__)
+#define STM32_USB_USE_OTG2 FALSE
+#endif
+
+/**
+ * @brief OTG1 interrupt priority level setting.
+ */
+#if !defined(STM32_USB_OTG1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_USB_OTG1_IRQ_PRIORITY 14
+#endif
+
+/**
+ * @brief OTG2 interrupt priority level setting.
+ */
+#if !defined(STM32_USB_OTG2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_USB_OTG2_IRQ_PRIORITY 14
+#endif
+
+/**
+ * @brief OTG1 RX shared FIFO size.
+ * @note Must be a multiple of 4.
+ */
+#if !defined(STM32_USB_OTG1_RX_FIFO_SIZE) || defined(__DOXYGEN__)
+#define STM32_USB_OTG1_RX_FIFO_SIZE 512
+#endif
+
+/**
+ * @brief OTG2 RX shared FIFO size.
+ * @note Must be a multiple of 4.
+ */
+#if !defined(STM32_USB_OTG2_RX_FIFO_SIZE) || defined(__DOXYGEN__)
+#define STM32_USB_OTG2_RX_FIFO_SIZE 1024
+#endif
+
+/**
+ * @brief Enables HS mode on OTG2 else FS mode.
+ * @note The default is @p TRUE.
+ * @note Has effect only if @p BOARD_OTG2_USES_ULPI is defined.
+ */
+#if !defined(STM32_USE_USB_OTG2_HS) || defined(__DOXYGEN__)
+#define STM32_USE_USB_OTG2_HS TRUE
+#endif
+
+/**
+ * @brief Exception priority level during TXFIFOs operations.
+ * @note Because an undocumented silicon behavior the operation of
+ * copying a packet into a TXFIFO must not be interrupted by
+ * any other operation on the OTG peripheral.
+ * This parameter represents the priority mask during copy
+ * operations. The default value only allows to call USB
+ * functions from callbacks invoked from USB ISR handlers.
+ * If you need to invoke USB functions from other handlers
+ * then raise this priority mast to the same level of the
+ * handler you need to use.
+ * @note The value zero means disabled, when disabled calling USB
+ * functions is only safe from thread level or from USB
+ * callbacks.
+ */
+#if !defined(STM32_USB_OTGFIFO_FILL_BASEPRI) || defined(__DOXYGEN__)
+#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
+#endif
+
+/**
+ * @brief Host wake-up procedure duration.
+ */
+#if !defined(STM32_USB_HOST_WAKEUP_DURATION) || defined(__DOXYGEN__)
+#define STM32_USB_HOST_WAKEUP_DURATION 2
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Registry checks.*/
+#if !defined(STM32_OTG_STEPPING)
+#error "STM32_OTG_STEPPING not defined in registry"
+#endif
+
+#if (STM32_OTG_STEPPING < 1) || (STM32_OTG_STEPPING > 2)
+#error "unsupported STM32_OTG_STEPPING"
+#endif
+
+#if !defined(STM32_HAS_OTG1) || !defined(STM32_HAS_OTG2)
+#error "STM32_HAS_OTGx not defined in registry"
+#endif
+
+#if STM32_HAS_OTG1 && !defined(STM32_OTG1_ENDPOINTS)
+#error "STM32_OTG1_ENDPOINTS not defined in registry"
+#endif
+
+#if STM32_HAS_OTG2 && !defined(STM32_OTG2_ENDPOINTS)
+#error "STM32_OTG2_ENDPOINTS not defined in registry"
+#endif
+
+#if STM32_HAS_OTG1 && !defined(STM32_OTG1_FIFO_MEM_SIZE)
+#error "STM32_OTG1_FIFO_MEM_SIZE not defined in registry"
+#endif
+
+#if STM32_HAS_OTG2 && !defined(STM32_OTG2_FIFO_MEM_SIZE)
+#error "STM32_OTG2_FIFO_MEM_SIZE not defined in registry"
+#endif
+
+#if (STM32_USB_USE_OTG1 && !defined(STM32_OTG1_HANDLER)) || \
+ (STM32_USB_USE_OTG2 && !defined(STM32_OTG2_HANDLER))
+#error "STM32_OTGx_HANDLER not defined in registry"
+#endif
+
+#if (STM32_USB_USE_OTG1 && !defined(STM32_OTG1_NUMBER)) || \
+ (STM32_USB_USE_OTG2 && !defined(STM32_OTG2_NUMBER))
+#error "STM32_OTGx_NUMBER not defined in registry"
+#endif
+
+/**
+ * @brief Maximum endpoint address.
+ */
+#if (STM32_HAS_OTG2 && STM32_USB_USE_OTG2) || defined(__DOXYGEN__)
+#if (STM32_OTG1_ENDPOINTS < STM32_OTG2_ENDPOINTS) || defined(__DOXYGEN__)
+#define USB_MAX_ENDPOINTS STM32_OTG2_ENDPOINTS
+#else
+#define USB_MAX_ENDPOINTS STM32_OTG1_ENDPOINTS
+#endif
+#else
+#define USB_MAX_ENDPOINTS STM32_OTG1_ENDPOINTS
+#endif
+
+#if STM32_USB_USE_OTG1 && !STM32_HAS_OTG1
+#error "OTG1 not present in the selected device"
+#endif
+
+#if STM32_USB_USE_OTG2 && !STM32_HAS_OTG2
+#error "OTG2 not present in the selected device"
+#endif
+
+#if !STM32_USB_USE_OTG1 && !STM32_USB_USE_OTG2
+#error "USB driver activated but no USB peripheral assigned"
+#endif
+
+#if STM32_USB_USE_OTG1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_OTG1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to OTG1"
+#endif
+
+#if STM32_USB_USE_OTG2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_OTG2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to OTG2"
+#endif
+
+#if (STM32_USB_OTG1_RX_FIFO_SIZE & 3) != 0
+#error "OTG1 RX FIFO size must be a multiple of 4"
+#endif
+
+#if (STM32_USB_OTG2_RX_FIFO_SIZE & 3) != 0
+#error "OTG2 RX FIFO size must be a multiple of 4"
+#endif
+
+#if defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX)
+#define STM32_USBCLK STM32_PLL48CLK
+#elif defined(STM32F10X_CL)
+#define STM32_USBCLK STM32_OTGFSCLK
+#elif defined(STM32L4XX) || defined(STM32L4XXP)
+#define STM32_USBCLK STM32_48CLK
+#elif defined(STM32H7XX)
+/* Defines directly STM32_USBCLK.*/
+#if !defined(STM32H723xx)
+#define rccEnableOTG_FS rccEnableUSB2_OTG_HS
+#define rccDisableOTG_FS rccDisableUSB2_OTG_HS
+#define rccResetOTG_FS rccResetUSB2_OTG_HS
+#else
+#define rccEnableOTG_FS rccEnableUSB1_OTG_HS
+#define rccDisableOTG_FS rccDisableUSB1_OTG_HS
+#define rccResetOTG_FS rccResetUSB1_OTG_HS
+#endif
+#define rccEnableOTG_HS rccEnableUSB1_OTG_HS
+#define rccDisableOTG_HS rccDisableUSB1_OTG_HS
+#define rccResetOTG_HS rccResetUSB1_OTG_HS
+#define rccEnableOTG_HSULPI rccEnableUSB1_HSULPI
+#define rccDisableOTG_HSULPI rccDisableUSB1_HSULPI
+#else
+#error "unsupported STM32 platform for OTG functionality"
+#endif
+
+/* Allowing for a small tolerance.*/
+#if STM32_USBCLK < 47880000 || STM32_USBCLK > 48120000
+#error "the USB OTG driver requires a 48MHz clock"
+#endif
+
+#if (STM32_USB_HOST_WAKEUP_DURATION < 2) || (STM32_USB_HOST_WAKEUP_DURATION > 15)
+#error "invalid STM32_USB_HOST_WAKEUP_DURATION setting, it must be between 2 and 15"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Peripheral-specific parameters block.
+ */
+typedef struct {
+ uint32_t rx_fifo_size;
+ uint32_t otg_ram_size;
+ uint32_t num_endpoints;
+} stm32_otg_params_t;
+
+/**
+ * @brief Type of an IN endpoint state structure.
+ */
+typedef struct {
+ /**
+ * @brief Requested transmit transfer size.
+ */
+ size_t txsize;
+ /**
+ * @brief Transmitted bytes so far.
+ */
+ size_t txcnt;
+ /**
+ * @brief Pointer to the transmission linear buffer.
+ */
+ const uint8_t *txbuf;
+#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ thread_reference_t thread;
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Total transmit transfer size.
+ */
+ size_t totsize;
+} USBInEndpointState;
+
+/**
+ * @brief Type of an OUT endpoint state structure.
+ */
+typedef struct {
+ /**
+ * @brief Requested receive transfer size.
+ */
+ size_t rxsize;
+ /**
+ * @brief Received bytes so far.
+ */
+ size_t rxcnt;
+ /**
+ * @brief Pointer to the receive linear buffer.
+ */
+ uint8_t *rxbuf;
+#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ thread_reference_t thread;
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Total receive transfer size.
+ */
+ size_t totsize;
+} USBOutEndpointState;
+
+/**
+ * @brief Type of an USB endpoint configuration structure.
+ * @note Platform specific restrictions may apply to endpoints.
+ */
+typedef struct {
+ /**
+ * @brief Type and mode of the endpoint.
+ */
+ uint32_t ep_mode;
+ /**
+ * @brief Setup packet notification callback.
+ * @details This callback is invoked when a setup packet has been
+ * received.
+ * @post The application must immediately call @p usbReadPacket() in
+ * order to access the received packet.
+ * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL
+ * endpoints, it should be set to @p NULL for other endpoint
+ * types.
+ */
+ usbepcallback_t setup_cb;
+ /**
+ * @brief IN endpoint notification callback.
+ * @details This field must be set to @p NULL if callback is not required.
+ */
+ usbepcallback_t in_cb;
+ /**
+ * @brief OUT endpoint notification callback.
+ * @details This field must be set to @p NULL if callback is not required.
+ */
+ usbepcallback_t out_cb;
+ /**
+ * @brief IN endpoint maximum packet size.
+ * @details This field must be set to zero if the IN endpoint is not used.
+ */
+ uint16_t in_maxsize;
+ /**
+ * @brief OUT endpoint maximum packet size.
+ * @details This field must be set to zero if the OUT endpoint is not used.
+ */
+ uint16_t out_maxsize;
+ /**
+ * @brief @p USBEndpointState associated to the IN endpoint.
+ * @details This field must be set to @p NULL if the IN endpoint is not
+ * used.
+ */
+ USBInEndpointState *in_state;
+ /**
+ * @brief @p USBEndpointState associated to the OUT endpoint.
+ * @details This field must be set to @p NULL if the OUT endpoint is not
+ * used.
+ */
+ USBOutEndpointState *out_state;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Determines the space allocated for the TXFIFO as multiples of
+ * the packet size (@p in_maxsize). Note that zero is interpreted
+ * as one for simplicity and robustness.
+ */
+ uint16_t in_multiplier;
+ /**
+ * @brief Pointer to a buffer for setup packets.
+ * @details Setup packets require a dedicated 8-bytes buffer, set this
+ * field to @p NULL for non-control endpoints.
+ */
+ uint8_t *setup_buf;
+} USBEndpointConfig;
+
+/**
+ * @brief Type of an USB driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief USB events callback.
+ * @details This callback is invoked when an USB driver event is registered.
+ */
+ usbeventcb_t event_cb;
+ /**
+ * @brief Device GET_DESCRIPTOR request callback.
+ * @note This callback is mandatory and cannot be set to @p NULL.
+ */
+ usbgetdescriptor_t get_descriptor_cb;
+ /**
+ * @brief Requests hook callback.
+ * @details This hook allows to be notified of standard requests or to
+ * handle non standard requests.
+ */
+ usbreqhandler_t requests_hook_cb;
+ /**
+ * @brief Start Of Frame callback.
+ */
+ usbcallback_t sof_cb;
+ /* End of the mandatory fields.*/
+} USBConfig;
+
+/**
+ * @brief Structure representing an USB driver.
+ */
+struct USBDriver {
+ /**
+ * @brief Driver state.
+ */
+ usbstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const USBConfig *config;
+ /**
+ * @brief Bit map of the transmitting IN endpoints.
+ */
+ uint16_t transmitting;
+ /**
+ * @brief Bit map of the receiving OUT endpoints.
+ */
+ uint16_t receiving;
+ /**
+ * @brief Active endpoints configurations.
+ */
+ const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1];
+ /**
+ * @brief Fields available to user, it can be used to associate an
+ * application-defined handler to an IN endpoint.
+ * @note The base index is one, the endpoint zero does not have a
+ * reserved element in this array.
+ */
+ void *in_params[USB_MAX_ENDPOINTS];
+ /**
+ * @brief Fields available to user, it can be used to associate an
+ * application-defined handler to an OUT endpoint.
+ * @note The base index is one, the endpoint zero does not have a
+ * reserved element in this array.
+ */
+ void *out_params[USB_MAX_ENDPOINTS];
+ /**
+ * @brief Endpoint 0 state.
+ */
+ usbep0state_t ep0state;
+ /**
+ * @brief Next position in the buffer to be transferred through endpoint 0.
+ */
+ uint8_t *ep0next;
+ /**
+ * @brief Number of bytes yet to be transferred through endpoint 0.
+ */
+ size_t ep0n;
+ /**
+ * @brief Endpoint 0 end transaction callback.
+ */
+ usbcallback_t ep0endcb;
+ /**
+ * @brief Setup packet buffer.
+ */
+ uint8_t setup[8];
+ /**
+ * @brief Current USB device status.
+ */
+ uint16_t status;
+ /**
+ * @brief Assigned USB address.
+ */
+ uint8_t address;
+ /**
+ * @brief Current USB device configuration.
+ */
+ uint8_t configuration;
+ /**
+ * @brief State of the driver when a suspend happened.
+ */
+ usbstate_t saved_state;
+#if defined(USB_DRIVER_EXT_FIELDS)
+ USB_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the OTG peripheral associated to this driver.
+ */
+ stm32_otg_t *otg;
+ /**
+ * @brief Peripheral-specific parameters.
+ */
+ const stm32_otg_params_t *otgparams;
+ /**
+ * @brief Pointer to the next address in the packet memory.
+ */
+ uint32_t pmnext;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Returns the exact size of a receive transaction.
+ * @details The received size can be different from the size specified in
+ * @p usbStartReceiveI() because the last packet could have a size
+ * different from the expected one.
+ * @pre The OUT endpoint must have been configured in transaction mode
+ * in order to use this function.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return Received data size.
+ *
+ * @notapi
+ */
+#define usb_lld_get_transaction_size(usbp, ep) \
+ ((usbp)->epc[ep]->out_state->rxcnt)
+
+/**
+ * @brief Connects the USB device.
+ *
+ * @notapi
+ */
+#if (STM32_OTG_STEPPING == 1) || defined(__DOXYGEN__)
+#define usb_lld_connect_bus(usbp) ((usbp)->otg->GCCFG |= GCCFG_VBUSBSEN)
+#else
+#define usb_lld_connect_bus(usbp) ((usbp)->otg->DCTL &= ~DCTL_SDIS)
+#endif
+
+/**
+ * @brief Disconnect the USB device.
+ *
+ * @notapi
+ */
+#if (STM32_OTG_STEPPING == 1) || defined(__DOXYGEN__)
+#define usb_lld_disconnect_bus(usbp) ((usbp)->otg->GCCFG &= ~GCCFG_VBUSBSEN)
+#else
+#define usb_lld_disconnect_bus(usbp) ((usbp)->otg->DCTL |= DCTL_SDIS)
+#endif
+
+/**
+ * @brief Start of host wake-up procedure.
+ *
+ * @notapi
+ */
+#define usb_lld_wakeup_host(usbp) \
+ do { \
+ (usbp)->otg->DCTL |= DCTL_RWUSIG; \
+ osalThreadSleepMilliseconds(STM32_USB_HOST_WAKEUP_DURATION); \
+ (usbp)->otg->DCTL &= ~DCTL_RWUSIG; \
+ } while (false)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_USB_USE_OTG1 && !defined(__DOXYGEN__)
+extern USBDriver USBD1;
+#endif
+
+#if STM32_USB_USE_OTG2 && !defined(__DOXYGEN__)
+extern USBDriver USBD2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void usb_lld_init(void);
+ void usb_lld_start(USBDriver *usbp);
+ void usb_lld_stop(USBDriver *usbp);
+ void usb_lld_reset(USBDriver *usbp);
+ void usb_lld_set_address(USBDriver *usbp);
+ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
+ void usb_lld_disable_endpoints(USBDriver *usbp);
+ usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
+ usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
+ void usb_lld_start_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_start_in(USBDriver *usbp, usbep_t ep);
+ void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
+ void usb_lld_clear_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_USB */
+
+#endif /* HAL_USB_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h new file mode 100644 index 0000000..0ea7314 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/OTGv1/stm32_otg.h @@ -0,0 +1,927 @@ +/*
+ 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 OTGv1/stm32_otg.h
+ * @brief STM32 OTG registers layout header.
+ *
+ * @addtogroup USB
+ * @{
+ */
+
+#ifndef STM32_OTG_H
+#define STM32_OTG_H
+
+/**
+ * @brief OTG_FS FIFO memory size in words.
+ */
+#define STM32_OTG1_FIFO_MEM_SIZE 320
+
+/**
+ * @brief OTG_HS FIFO memory size in words.
+ */
+#define STM32_OTG2_FIFO_MEM_SIZE 1024
+
+/**
+ * @brief Host channel registers group.
+ */
+typedef struct {
+ volatile uint32_t HCCHAR; /**< @brief Host channel characteristics
+ register. */
+ volatile uint32_t resvd8;
+ volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/
+ volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask
+ register. */
+ volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size
+ register. */
+ volatile uint32_t resvd14;
+ volatile uint32_t resvd18;
+ volatile uint32_t resvd1c;
+} stm32_otg_host_chn_t;
+
+/**
+ * @brief Device input endpoint registers group.
+ */
+typedef struct {
+ volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint
+ control register. */
+ volatile uint32_t resvd4;
+ volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt
+ register. */
+ volatile uint32_t resvdC;
+ volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size
+ register. */
+ volatile uint32_t resvd14;
+ volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO
+ status register. */
+ volatile uint32_t resvd1C;
+} stm32_otg_in_ep_t;
+
+/**
+ * @brief Device output endpoint registers group.
+ */
+typedef struct {
+ volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint
+ control register. */
+ volatile uint32_t resvd4;
+ volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt
+ register. */
+ volatile uint32_t resvdC;
+ volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer
+ size register. */
+ volatile uint32_t resvd14;
+ volatile uint32_t resvd18;
+ volatile uint32_t resvd1C;
+} stm32_otg_out_ep_t;
+
+/**
+ * @brief USB registers memory map.
+ */
+typedef struct {
+ volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/
+ volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */
+ volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */
+ volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */
+ volatile uint32_t GRSTCTL; /**< @brief Reset register size. */
+ volatile uint32_t GINTSTS; /**< @brief Interrupt register. */
+ volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */
+ volatile uint32_t GRXSTSR; /**< @brief Receive status debug read
+ register. */
+ volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop
+ register. */
+ volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */
+ volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size
+ register. */
+ volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue
+ status register. */
+ volatile uint32_t resvd30;
+ volatile uint32_t resvd34;
+ volatile uint32_t GCCFG; /**< @brief General core configuration. */
+ volatile uint32_t CID; /**< @brief Core ID register. */
+ volatile uint32_t resvd58[48];
+ volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size
+ register. */
+ volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO
+ size registers. */
+ volatile uint32_t resvd140[176];
+ volatile uint32_t HCFG; /**< @brief Host configuration register. */
+ volatile uint32_t HFIR; /**< @brief Host frame interval register. */
+ volatile uint32_t HFNUM; /**< @brief Host frame number/frame time
+ Remaining register. */
+ volatile uint32_t resvd40C;
+ volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue
+ status register. */
+ volatile uint32_t HAINT; /**< @brief Host all channels interrupt
+ register. */
+ volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask
+ register. */
+ volatile uint32_t resvd41C[9];
+ volatile uint32_t HPRT; /**< @brief Host port control and status
+ register. */
+ volatile uint32_t resvd444[47];
+ stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */
+ volatile uint32_t resvd700[64];
+ volatile uint32_t DCFG; /**< @brief Device configuration register. */
+ volatile uint32_t DCTL; /**< @brief Device control register. */
+ volatile uint32_t DSTS; /**< @brief Device status register. */
+ volatile uint32_t resvd80C;
+ volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common
+ interrupt mask register. */
+ volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common
+ interrupt mask register. */
+ volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt
+ register. */
+ volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt
+ mask register. */
+ volatile uint32_t resvd820;
+ volatile uint32_t resvd824;
+ volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time
+ register. */
+ volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time
+ register. */
+ volatile uint32_t resvd830;
+ volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty
+ interrupt mask register. */
+ volatile uint32_t resvd838;
+ volatile uint32_t resvd83C;
+ volatile uint32_t resvd840[16];
+ volatile uint32_t resvd880[16];
+ volatile uint32_t resvd8C0[16];
+ stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */
+ stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */
+ volatile uint32_t resvdD00[64];
+ volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control
+ register. */
+ volatile uint32_t resvdE04[127];
+ volatile uint32_t FIFO[16][1024];
+} stm32_otg_t;
+
+/**
+ * @name GOTGCTL register bit definitions
+ * @{
+ */
+#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */
+#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */
+#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */
+#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */
+#define GOTGCTL_EHEN (1U<<12)
+#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */
+#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */
+#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */
+#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */
+#define GOTGCTL_BVALOVAL (1U<<7)
+#define GOTGCTL_BVALOEN (1U<<6)
+#define GOTGCTL_AVALOVAL (1U<<5)
+#define GOTGCTL_AVALOEN (1U<<4)
+#define GOTGCTL_VBVALOVAL (1U<<3)
+#define GOTGCTL_VBVALOEN (1U<<2)
+#define GOTGCTL_SRQ (1U<<1) /**< Session request. */
+#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */
+/** @} */
+
+/**
+ * @name GOTGINT register bit definitions
+ * @{
+ */
+#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */
+#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */
+#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */
+#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success
+ status change. */
+#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success
+ status change. */
+#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */
+/** @} */
+
+/**
+ * @name GAHBCFG register bit definitions
+ * @{
+ */
+#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty
+ level. */
+#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty
+ level. */
+#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */
+#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS
+ only). */
+#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS
+ only). */
+#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */
+/** @} */
+
+/**
+ * @name GUSBCFG register bit definitions
+ * @{
+ */
+#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */
+#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */
+#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */
+#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field
+ mask. */
+#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field
+ value. */
+#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */
+#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */
+#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or
+ USB 1.1 Full-Speed serial
+ transceiver Select. */
+#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration
+ field mask. */
+#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration
+ field value. */
+/** @} */
+
+/**
+ * @name GRSTCTL register bit definitions
+ * @{
+ */
+#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */
+#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */
+#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */
+#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */
+#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */
+#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */
+#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */
+#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */
+/** @} */
+
+/**
+ * @name GINTSTS register bit definitions
+ * @{
+ */
+#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup
+ detected interrupt. */
+#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session
+ detected interrupt. */
+#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected
+ interrupt. */
+#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/
+#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */
+#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */
+#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */
+#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic
+ transfer. */
+#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT
+ transfer. */
+#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN
+ transfer. */
+#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */
+#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */
+#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame
+ interrupt. */
+#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet
+ dropped interrupt. */
+#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */
+#define GINTSTS_USBRST (1U<<12) /**< USB reset. */
+#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */
+#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */
+#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */
+#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK
+ effective. */
+#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */
+#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */
+#define GINTSTS_SOF (1U<<3) /**< Start of frame. */
+#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */
+#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */
+#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */
+/** @} */
+
+/**
+ * @name GINTMSK register bit definitions
+ * @{
+ */
+#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup
+ detected interrupt mask. */
+#define GINTMSK_SRQM (1U<<30) /**< Session request/New session
+ detected interrupt mask. */
+#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected
+ interrupt mask. */
+#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change
+ mask. */
+#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/
+#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt
+ mask. */
+#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */
+#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic
+ transfer mask. */
+#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT
+ transfer mask. */
+#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN
+ transfer mask. */
+#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt
+ mask. */
+#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt
+ mask. */
+#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame
+ interrupt mask. */
+#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet
+ dropped interrupt mask. */
+#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */
+#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */
+#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */
+#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */
+#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective
+ mask. */
+#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK
+ effective mask. */
+#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty
+ mask. */
+#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty
+ mask. */
+#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/
+#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */
+#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt
+ mask. */
+/** @} */
+
+/**
+ * @name GRXSTSR register bit definitions
+ * @{
+ */
+#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */
+#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */
+#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1)
+#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2)
+#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3)
+#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4)
+#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6)
+#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */
+#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */
+#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
+#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */
+#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */
+#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */
+#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
+#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
+/** @} */
+
+/**
+ * @name GRXSTSP register bit definitions
+ * @{
+ */
+#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */
+#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */
+#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1)
+#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2)
+#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3)
+#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4)
+#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6)
+#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */
+#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */
+#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
+#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */
+#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */
+#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */
+#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */
+#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
+#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */
+#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
+/** @} */
+
+/**
+ * @name GRXFSIZ register bit definitions
+ * @{
+ */
+#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */
+#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */
+/** @} */
+
+/**
+ * @name DIEPTXFx register bit definitions
+ * @{
+ */
+#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth
+ mask. */
+#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth
+ value. */
+#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit
+ RAM start address mask. */
+#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit
+ RAM start address value. */
+/** @} */
+
+/**
+ * @name GCCFG register bit definitions
+ * @{
+ */
+/* Definitions for stepping 1.*/
+#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */
+#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */
+#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B"
+ device. */
+#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A"
+ device. */
+
+/* Definitions for stepping 2.*/
+#define GCCFG_VBDEN (1U<<21) /**< VBUS sensing enable. */
+#define GCCFG_PWRDWN (1U<<16) /**< Power down. */
+/** @} */
+
+/**
+ * @name HPTXFSIZ register bit definitions
+ * @{
+ */
+#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO
+ depth mask. */
+#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO
+ depth value. */
+#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO
+ Start address mask. */
+#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO
+ start address value. */
+/** @} */
+
+/**
+ * @name HCFG register bit definitions
+ * @{
+ */
+#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */
+#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select
+ mask. */
+#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at
+ 48 MHz. */
+#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at
+ 6 MHz. */
+/** @} */
+
+/**
+ * @name HFIR register bit definitions
+ * @{
+ */
+#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */
+#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */
+/** @} */
+
+/**
+ * @name HFNUM register bit definitions
+ * @{
+ */
+#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/
+#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/
+#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */
+#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */
+/** @} */
+
+/**
+ * @name HPTXSTS register bit definitions
+ * @{
+ */
+#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic
+ transmit request queue
+ mask. */
+#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic
+ transmit request queue
+ value. */
+#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request
+ queue Space Available
+ mask. */
+#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request
+ queue Space Available
+ value. */
+#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data
+ FIFO Space Available
+ mask. */
+#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data
+ FIFO Space Available
+ value. */
+/** @} */
+
+/**
+ * @name HAINT register bit definitions
+ * @{
+ */
+#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */
+#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */
+/** @} */
+
+/**
+ * @name HAINTMSK register bit definitions
+ * @{
+ */
+#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask
+ mask. */
+#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask
+ value. */
+/** @} */
+
+/**
+ * @name HPRT register bit definitions
+ * @{
+ */
+#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */
+#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */
+#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */
+#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */
+#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */
+#define HPRT_PPWR (1U<<12) /**< Port power. */
+#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */
+#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */
+#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */
+#define HPRT_PRST (1U<<8) /**< Port reset. */
+#define HPRT_PSUSP (1U<<7) /**< Port suspend. */
+#define HPRT_PRES (1U<<6) /**< Port Resume. */
+#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */
+#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */
+#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/
+#define HPRT_PENA (1U<<2) /**< Port enable. */
+#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */
+#define HPRT_PCSTS (1U<<0) /**< Port connect status. */
+/** @} */
+
+/**
+ * @name HCCHAR register bit definitions
+ * @{
+ */
+#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */
+#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */
+#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */
+#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */
+#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */
+#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */
+#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */
+#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
+#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */
+#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */
+#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/
+#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */
+#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */
+#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */
+#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */
+#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */
+#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */
+#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */
+#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */
+/** @} */
+
+/**
+ * @name HCINT register bit definitions
+ * @{
+ */
+#define HCINT_DTERR (1U<<10) /**< Data toggle error. */
+#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */
+#define HCINT_BBERR (1U<<8) /**< Babble error. */
+#define HCINT_TRERR (1U<<7) /**< Transaction Error. */
+#define HCINT_ACK (1U<<5) /**< ACK response
+ received/transmitted
+ interrupt. */
+#define HCINT_NAK (1U<<4) /**< NAK response received
+ interrupt. */
+#define HCINT_STALL (1U<<3) /**< STALL response received
+ interrupt. */
+#define HCINT_AHBERR (1U<<2) /**< AHB error interrupt. */
+#define HCINT_CHH (1U<<1) /**< Channel halted. */
+#define HCINT_XFRC (1U<<0) /**< Transfer completed. */
+/** @} */
+
+/**
+ * @name HCINTMSK register bit definitions
+ * @{
+ */
+#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */
+#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */
+#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */
+#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */
+#define HCINTMSK_NYET (1U<<6) /**< NYET response received
+ interrupt mask. */
+#define HCINTMSK_ACKM (1U<<5) /**< ACK Response
+ received/transmitted
+ interrupt mask. */
+#define HCINTMSK_NAKM (1U<<4) /**< NAK response received
+ interrupt mask. */
+#define HCINTMSK_STALLM (1U<<3) /**< STALL response received
+ interrupt mask. */
+#define HCINTMSK_AHBERRM (1U<<2) /**< AHB error interrupt mask. */
+#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */
+#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */
+/** @} */
+
+/**
+ * @name HCTSIZ register bit definitions
+ * @{
+ */
+#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */
+#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */
+#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */
+#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */
+#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */
+#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */
+#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
+#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
+#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */
+#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
+/** @} */
+
+/**
+ * @name DCFG register bit definitions
+ * @{
+ */
+#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval
+ mask. */
+#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval
+ value. */
+#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */
+#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */
+#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status
+ OUT handshake. */
+#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */
+#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */
+#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS
+ mode. */
+#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1
+ transceiver clock is 48
+ MHz). */
+/** @} */
+
+/**
+ * @name DCTL register bit definitions
+ * @{
+ */
+#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */
+#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */
+#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */
+#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic
+ IN NAK. */
+#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic
+ IN NAK. */
+#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */
+#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */
+#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */
+#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN
+ NAK status. */
+#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */
+#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */
+/** @} */
+
+/**
+ * @name DSTS register bit definitions
+ * @{
+ */
+#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received
+ SOF mask. */
+#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received
+ SOF value. */
+#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received
+ SOF value. */
+#define DSTS_EERR (1U<<3) /**< Erratic error. */
+#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */
+#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is
+ running at 48 MHz). */
+#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */
+#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */
+/** @} */
+
+/**
+ * @name DIEPMSK register bit definitions
+ * @{
+ */
+#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */
+#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective
+ mask. */
+#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when
+ TxFIFO empty mask. */
+#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */
+#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled
+ interrupt mask. */
+#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed
+ interrupt mask. */
+/** @} */
+
+/**
+ * @name DOEPMSK register bit definitions
+ * @{
+ */
+#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when
+ endpoint disabled mask. */
+#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */
+#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled
+ interrupt mask. */
+#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed
+ interrupt mask. */
+/** @} */
+
+/**
+ * @name DAINT register bit definitions
+ * @{
+ */
+#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt
+ bits mask. */
+#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt
+ bits value. */
+#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt
+ bits mask. */
+#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt
+ bits value. */
+/** @} */
+
+/**
+ * @name DAINTMSK register bit definitions
+ * @{
+ */
+#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask
+ bits mask. */
+#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask
+ bits value. */
+#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask
+ bits mask. */
+#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask
+ bits value. */
+/** @} */
+
+/**
+ * @name DVBUSDIS register bit definitions
+ * @{
+ */
+#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge
+ time mask. */
+#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge
+ time value. */
+/** @} */
+
+/**
+ * @name DVBUSPULSE register bit definitions
+ * @{
+ */
+#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time
+ mask. */
+#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time
+ value. */
+/** @} */
+
+/**
+ * @name DIEPEMPMSK register bit definitions
+ * @{
+ */
+#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty
+ interrupt mask bit. */
+/** @} */
+
+/**
+ * @name DIEPCTL register bit definitions
+ * @{
+ */
+#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
+#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
+#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
+#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
+#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
+#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
+#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */
+#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */
+#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */
+#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */
+#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */
+#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */
+#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */
+#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
+#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
+#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
+#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
+#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */
+#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
+#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
+#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
+#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
+#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
+/** @} */
+
+/**
+ * @name DIEPINT register bit definitions
+ * @{
+ */
+#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */
+#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */
+#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when
+ TxFIFO is empty. */
+#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */
+#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled
+ interrupt. */
+#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */
+/** @} */
+
+/**
+ * @name DIEPTSIZ register bit definitions
+ * @{
+ */
+#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */
+#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */
+#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */
+#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
+#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
+#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
+/** @} */
+
+/**
+ * @name DTXFSTS register bit definitions.
+ * @{
+ */
+#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space
+ available. */
+/** @} */
+
+/**
+ * @name DOEPCTL register bit definitions.
+ * @{
+ */
+#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
+#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
+#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
+#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
+#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
+#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
+#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */
+#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */
+#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */
+#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */
+#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
+#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
+#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
+#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
+#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
+#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */
+#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
+#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
+#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
+#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
+#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
+/** @} */
+
+/**
+ * @name DOEPINT register bit definitions
+ * @{
+ */
+#define DOEPINT_SETUP_RCVD (1U<<15) /**< SETUP packet received. */
+#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets
+ received. */
+#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when
+ endpoint disabled. */
+#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */
+#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled
+ interrupt. */
+#define DOEPINT_XFRC (1U<<0) /**< Transfer completed
+ interrupt. */
+/** @} */
+
+/**
+ * @name DOEPTSIZ register bit definitions
+ * @{
+ */
+#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */
+#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */
+#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */
+#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */
+#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
+#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
+#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
+#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
+/** @} */
+
+/**
+ * @name PCGCCTL register bit definitions
+ * @{
+ */
+#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */
+#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */
+#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */
+/** @} */
+
+#if defined(STM32H7XX) || defined(__DOXYGEN__)
+/**
+ * @brief OTG_FS registers block memory address.
+ */
+#define OTG_FS_ADDR 0x40080000
+
+/**
+ * @brief OTG_HS registers block memory address.
+ */
+#define OTG_HS_ADDR 0x40040000
+#else
+#define OTG_FS_ADDR 0x50000000
+#define OTG_HS_ADDR 0x40040000
+#endif
+
+/**
+ * @brief Accesses to the OTG_FS registers block.
+ */
+#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR)
+
+/**
+ * @brief Accesses to the OTG_HS registers block.
+ */
+#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR)
+
+#endif /* STM32_OTG_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk new file mode 100644 index 0000000..e59aec0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_WSPI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c new file mode 100644 index 0000000..678339a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c @@ -0,0 +1,375 @@ +/*
+ 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 QUADSPIv1//hal_wspi_lld.c
+ * @brief STM32 WSPI subsystem low level driver source.
+ *
+ * @addtogroup WSPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define QUADSPI1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_WSPI_QUADSPI1_DMA_STREAM, \
+ STM32_QUADSPI1_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief QUADSPI1 driver identifier.*/
+#if STM32_WSPI_USE_QUADSPI1 || defined(__DOXYGEN__)
+WSPIDriver WSPID1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Waits for completion of previous operation.
+ */
+static inline void wspi_lld_sync(WSPIDriver *wspip) {
+
+ while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) {
+ }
+}
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void wspi_lld_serve_dma_interrupt(WSPIDriver *wspip, uint32_t flags) {
+
+ (void)wspip;
+ (void)flags;
+
+ /* DMA errors handling.*/
+#if defined(STM32_WSPI_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_WSPI_DMA_ERROR_HOOK(wspip);
+ }
+#endif
+}
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ */
+static void wspi_lld_serve_interrupt(WSPIDriver *wspip) {
+
+ /* Portable WSPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _wspi_isr_code(wspip);
+
+ /* Stop everything, we need to give DMA enough time to complete the ongoing
+ operation. Race condition hidden here.*/
+ while (dmaStreamGetTransactionSize(wspip->dma) > 0U)
+ ;
+
+ /* Handling of errata: Extra data written in the FIFO at the end of a
+ read transfer.*/
+ if (wspip->state == WSPI_RECEIVE) {
+ while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) {
+ (void) wspip->qspi->DR;
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_WSPI_USE_QUADSPI1 || defined(__DOXYGEN__)
+#if !defined(STM32_QUADSPI1_SUPPRESS_ISR)
+#if !defined(STM32_QUADSPI1_HANDLER)
+#error "STM32_QUADSPI1_HANDLER not defined"
+#endif
+/**
+ * @brief STM32_QUADSPI1_HANDLER interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_QUADSPI1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ QUADSPI->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF |
+ QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF;
+
+ wspi_lld_serve_interrupt(&WSPID1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_QUADSPI1_SUPPRESS_ISR) */
+#endif /* STM32_WSPI_USE_QUADSPI1 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level WSPI driver initialization.
+ *
+ * @notapi
+ */
+void wspi_lld_init(void) {
+
+#if STM32_WSPI_USE_QUADSPI1
+ wspiObjectInit(&WSPID1);
+ WSPID1.qspi = QUADSPI;
+ WSPID1.dma = NULL;
+ WSPID1.dmamode = STM32_DMA_CR_CHSEL(QUADSPI1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_WSPI_QUADSPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_BYTE |
+ STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ nvicEnableVector(STM32_QUADSPI1_NUMBER, STM32_WSPI_QUADSPI1_IRQ_PRIORITY);
+#endif
+}
+
+/**
+ * @brief Configures and activates the WSPI peripheral.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_start(WSPIDriver *wspip) {
+
+ /* If in stopped state then full initialization.*/
+ if (wspip->state == WSPI_STOP) {
+#if STM32_WSPI_USE_QUADSPI1
+ if (&WSPID1 == wspip) {
+ wspip->dma = dmaStreamAllocI(STM32_WSPI_QUADSPI1_DMA_STREAM,
+ STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY,
+ (stm32_dmaisr_t)wspi_lld_serve_dma_interrupt,
+ (void *)wspip);
+ osalDbgAssert(wspip->dma != NULL, "unable to allocate stream");
+ rccEnableQUADSPI1(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(wspip->dma, STM32_DMAMUX1_QUADSPI);
+#endif
+ }
+#endif
+
+ /* Common initializations.*/
+ dmaStreamSetPeripheral(wspip->dma, &wspip->qspi->DR);
+ }
+
+ /* WSPI setup and enable.*/
+ wspip->qspi->DCR = wspip->config->dcr;
+ wspip->qspi->CR = ((STM32_WSPI_QUADSPI1_PRESCALER_VALUE - 1U) << 24U) |
+ QUADSPI_CR_TCIE | QUADSPI_CR_DMAEN | QUADSPI_CR_EN;
+ wspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF |
+ QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF;
+}
+
+/**
+ * @brief Deactivates the WSPI peripheral.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_stop(WSPIDriver *wspip) {
+
+ /* If in ready state then disables the QUADSPI clock.*/
+ if (wspip->state == WSPI_READY) {
+
+ /* WSPI disable.*/
+ wspip->qspi->CR = 0U;
+
+ /* Releasing the DMA.*/
+ dmaStreamFreeI(wspip->dma);
+ wspip->dma = NULL;
+
+ /* Stopping involved clocks.*/
+#if STM32_WSPI_USE_QUADSPI1
+ if (&WSPID1 == wspip) {
+ rccDisableQUADSPI1();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Sends a command without data phase.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ *
+ * @notapi
+ */
+void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp) {
+
+#if STM32_USE_STM32_D1_WORKAROUND == TRUE
+ /* If it is a command without address and alternate phases then the command
+ is sent as an alternate byte, the command phase is suppressed.*/
+ if ((cmdp->cfg & (WSPI_CFG_ADDR_MODE_MASK | WSPI_CFG_ALT_MODE_MASK)) == 0U) {
+ /* The command mode field is copied in the alternate mode field. All
+ other fields are not used in this scenario.*/
+ wspip->qspi->DLR = 0U;
+ wspip->qspi->ABR = cmdp->cmd;
+ wspip->qspi->CCR = (cmdp->cfg & WSPI_CFG_CMD_MODE_MASK) << 6U;
+ return;
+ }
+#endif
+ wspip->qspi->DLR = 0U;
+ wspip->qspi->ABR = cmdp->alt;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->qspi->AR = cmdp->addr;
+ }
+
+ /* Waiting for the previous operation to complete.*/
+ wspi_lld_sync(wspip);
+}
+
+/**
+ * @brief Sends a command with data over the WSPI bus.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[in] n number of bytes to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, const uint8_t *txbuf) {
+
+ dmaStreamSetMemory0(wspip->dma, txbuf);
+ dmaStreamSetTransactionSize(wspip->dma, n);
+ dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_M2P);
+
+ wspip->qspi->DLR = n - 1;
+ wspip->qspi->ABR = cmdp->alt;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->qspi->AR = cmdp->addr;
+ }
+
+ dmaStreamEnable(wspip->dma);
+}
+
+/**
+ * @brief Sends a command then receives data over the WSPI bus.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[in] n number of bytes to send
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, uint8_t *rxbuf) {
+
+ dmaStreamSetMemory0(wspip->dma, rxbuf);
+ dmaStreamSetTransactionSize(wspip->dma, n);
+ dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_P2M);
+
+ wspip->qspi->DLR = n - 1;
+ wspip->qspi->ABR = cmdp->alt;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg |
+ QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) |
+ QUADSPI_CCR_FMODE_0;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->qspi->AR = cmdp->addr;
+ }
+
+ dmaStreamEnable(wspip->dma);
+}
+
+#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Maps in memory space a WSPI flash device.
+ * @pre The memory flash device must be initialized appropriately
+ * before mapping it in memory space.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[out] addrp pointer to the memory start address of the mapped
+ * flash or @p NULL
+ *
+ * @notapi
+ */
+void wspi_lld_map_flash(WSPIDriver *wspip,
+ const wspi_command_t *cmdp,
+ uint8_t **addrp) {
+
+ /* Disabling the DMA request while in memory mapped mode.*/
+ wspip->qspi->CR &= ~QUADSPI_CR_DMAEN;
+
+ /* Starting memory mapped mode using the passed parameters.*/
+ wspip->qspi->DLR = 0;
+ wspip->qspi->ABR = 0;
+ wspip->qspi->AR = 0;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg |
+ QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) |
+ QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0;
+
+ /* Mapped flash absolute base address.*/
+ if (addrp != NULL) {
+ *addrp = (uint8_t *)0x90000000;
+ }
+}
+
+/**
+ * @brief Unmaps from memory space a WSPI flash device.
+ * @post The memory flash device must be re-initialized for normal
+ * commands exchange.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_unmap_flash(WSPIDriver *wspip) {
+
+ /* Aborting memory mapped mode.*/
+ wspip->qspi->CR |= QUADSPI_CR_ABORT;
+ while ((wspip->qspi->CR & QUADSPI_CR_ABORT) != 0U) {
+ }
+
+ /* Re-enabling DMA request, we are going back to indirect mode.*/
+ wspip->qspi->CR |= QUADSPI_CR_DMAEN;
+}
+#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */
+
+#endif /* HAL_USE_WSPI */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h new file mode 100644 index 0000000..5ebbd06 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.h @@ -0,0 +1,313 @@ +/*
+ 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 QUADSPIv1/hal_wspi_lld.h
+ * @brief STM32 WSPI subsystem low level driver header.
+ *
+ * @addtogroup WSPI
+ * @{
+ */
+
+#ifndef HAL_WSPI_LLD_H
+#define HAL_WSPI_LLD_H
+
+#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name WSPI implementation capabilities
+ * @{
+ */
+#define WSPI_SUPPORTS_MEMMAP TRUE
+#define WSPI_DEFAULT_CFG_MASKS FALSE
+/** @} */
+
+/**
+ * @name Transfer options
+ * @note The low level driver has the option to override the following
+ * definitions and use its own ones. In must take care to use
+ * the same name for the same function or compatibility is not
+ * ensured.
+ * @note There are the following limitations in this implementation:
+ * - Eight lines are not supported.
+ * - DDR mode is only supported for the whole command, separate
+ * masks are defined but all define the same bit.
+ * - Only 8 bits instructions are supported.
+ * .
+ * @{
+ */
+#define WSPI_CFG_CMD_MODE_MASK (3LU << 8LU)
+#define WSPI_CFG_CMD_MODE_NONE (0LU << 8LU)
+#define WSPI_CFG_CMD_MODE_ONE_LINE (1LU << 8LU)
+#define WSPI_CFG_CMD_MODE_TWO_LINES (2LU << 8LU)
+#define WSPI_CFG_CMD_MODE_FOUR_LINES (3LU << 8LU)
+
+#define WSPI_CFG_CMD_DDR (1LU << 31LU)
+
+#define WSPI_CFG_CMD_SIZE_MASK 0LU
+#define WSPI_CFG_CMD_SIZE_8 0LU
+
+#define WSPI_CFG_ADDR_MODE_MASK (3LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_NONE (0LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_ONE_LINE (1LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_TWO_LINES (2LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_FOUR_LINES (3LU << 10LU)
+
+#define WSPI_CFG_ADDR_DDR (1LU << 31LU)
+
+#define WSPI_CFG_ADDR_SIZE_MASK (3LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_8 (0LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_16 (1LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_24 (2LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_32 (3LU << 12LU)
+
+#define WSPI_CFG_ALT_MODE_MASK (3LU << 14LU)
+#define WSPI_CFG_ALT_MODE_NONE (0LU << 14LU)
+#define WSPI_CFG_ALT_MODE_ONE_LINE (1LU << 14LU)
+#define WSPI_CFG_ALT_MODE_TWO_LINES (2LU << 14LU)
+#define WSPI_CFG_ALT_MODE_FOUR_LINES (3LU << 14LU)
+
+#define WSPI_CFG_ALT_DDR (1LU << 31LU)
+
+#define WSPI_CFG_ALT_SIZE_MASK (3LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_8 (0LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_16 (1LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_24 (2LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_32 (3LU << 16LU)
+
+#define WSPI_CFG_DATA_MODE_MASK (3LU << 24LU)
+#define WSPI_CFG_DATA_MODE_NONE (0LU << 24LU)
+#define WSPI_CFG_DATA_MODE_ONE_LINE (1LU << 24LU)
+#define WSPI_CFG_DATA_MODE_TWO_LINES (2LU << 24LU)
+#define WSPI_CFG_DATA_MODE_FOUR_LINES (3LU << 24LU)
+
+#define WSPI_CFG_DATA_DDR (1LU << 31LU)
+
+#define WSPI_CFG_SIOO (1LU << 28LU)
+/** @} */
+
+/**
+ * @name Helpers for CCR register.
+ * @{
+ */
+#define QUADSPI_CCR_DUMMY_CYCLES_MASK (0x1FLU << 18LU)
+#define QUADSPI_CCR_DUMMY_CYCLES(n) ((n) << 18LU)
+/** @} */
+
+/**
+ * @name DCR register options
+ * @{
+ */
+#define STM32_DCR_CK_MODE (1U << 0U)
+#define STM32_DCR_CSHT_MASK (7U << 8U)
+#define STM32_DCR_CSHT(n) ((n) << 8U)
+#define STM32_DCR_FSIZE_MASK (31U << 16U)
+#define STM32_DCR_FSIZE(n) ((n) << 16U)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief WSPID1 driver enable switch.
+ * @details If set to @p TRUE the support for QUADSPI1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_WSPI_USE_QUADSPI1) || defined(__DOXYGEN__)
+#define STM32_WSPI_USE_QUADSPI1 FALSE
+#endif
+
+/**
+ * @brief QUADSPI1 prescaler setting.
+ * @note This is the prescaler divider value 1..256. The maximum frequency
+ * varies depending on the STM32 model and operating conditions,
+ * find the details in the data sheet.
+ */
+#if !defined(STM32_WSPI_QUADSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__)
+#define STM32_WSPI_QUADSPI1_PRESCALER_VALUE 1
+#endif
+
+/**
+ * @brief QUADSPI1 interrupt priority level setting.
+ */
+#if !defined(STM32_WSPI_QUADSPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_QUADSPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief QUADSPI1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_WSPI_QUADSPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_QUADSPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief QUADSPI1 DMA interrupt priority level setting.
+ */
+#if !defined(STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief QUADSPI DMA error hook.
+ */
+#if !defined(STM32_WSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_WSPI_DMA_ERROR_HOOK(qspip) osalSysHalt("DMA failure")
+#endif
+
+/**
+ * @brief Enables a workaround for a STM32L476 QUADSPI errata.
+ * @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an
+ * input when the command is sent in dual or quad SPI mode".
+ * This workaround makes commands without address or data phases
+ * to be sent as alternate bytes.
+ */
+#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__)
+#define STM32_USE_STM32_D1_WORKAROUND TRUE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_QUADSPI1)
+#define STM32_HAS_QUADSPI1 FALSE
+#endif
+
+#if STM32_WSPI_USE_QUADSPI1 && !STM32_HAS_QUADSPI1
+#error "QUADSPI1 not present in the selected device"
+#endif
+
+#if !STM32_WSPI_USE_QUADSPI1
+#error "WSPI driver activated but no QUADSPI peripheral assigned"
+#endif
+
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to QUADSPI1"
+#endif
+
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_DMA_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to QUADSPI1 DMA"
+#endif
+
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to QUADSPI1"
+#endif
+
+#if (STM32_WSPI_QUADSPI1_PRESCALER_VALUE < 1) || \
+ (STM32_WSPI_QUADSPI1_PRESCALER_VALUE > 256)
+#error "STM32_WSPI_QUADSPI1_PRESCALER_VALUE not within 1..256"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_WSPI_USE_QUADSPI1 && !defined(STM32_WSPI_QUADSPI1_DMA_STREAM)
+#error "QUADSPI1 DMA stream not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_WSPI_QUADSPI1_DMA_STREAM)
+#error "invalid DMA stream associated to QUADSPI1"
+#endif
+
+/* Devices without DMAMUX require an additional check.*/
+#if !STM32_DMA_SUPPORTS_DMAMUX
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_WSPI_QUADSPI1_DMA_STREAM, STM32_QUADSPI1_DMA_MSK)
+#error "invalid DMA stream associated to QUADSPI1"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the WSPI configuration structure.
+ */
+#define wspi_lld_config_fields \
+ /* DCR register initialization data.*/ \
+ uint32_t dcr
+
+/**
+ * @brief Low level fields of the WSPI driver structure.
+ */
+#define wspi_lld_driver_fields \
+ /* Pointer to the QUADSPIx registers block.*/ \
+ QUADSPI_TypeDef *qspi; \
+ /* QUADSPI DMA stream.*/ \
+ const stm32_dma_stream_t *dma; \
+ /* QUADSPI DMA mode bit mask.*/ \
+ uint32_t dmamode
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if (STM32_WSPI_USE_QUADSPI1 == TRUE) && !defined(__DOXYGEN__)
+extern WSPIDriver WSPID1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void wspi_lld_init(void);
+ void wspi_lld_start(WSPIDriver *wspip);
+ void wspi_lld_stop(WSPIDriver *wspip);
+ void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp);
+ void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, const uint8_t *txbuf);
+ void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, uint8_t *rxbuf);
+#if WSPI_SUPPORTS_MEMMAP == TRUE
+ void wspi_lld_map_flash(WSPIDriver *wspip,
+ const wspi_command_t *cmdp,
+ uint8_t **addrp);
+ void wspi_lld_unmap_flash(WSPIDriver *wspip);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_WSPI */
+
+#endif /* HAL_WSPI_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk new file mode 100644 index 0000000..0a9e099 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_WSPI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c new file mode 100644 index 0000000..118556b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.c @@ -0,0 +1,356 @@ +/*
+ 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 QUADSPIv2//hal_wspi_lld.c
+ * @brief STM32 WSPI subsystem low level driver source.
+ *
+ * @addtogroup WSPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief QUADSPI1 driver identifier.*/
+#if STM32_WSPI_USE_QUADSPI1 || defined(__DOXYGEN__)
+WSPIDriver WSPID1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Waits for completion of previous operation.
+ */
+static inline void wspi_lld_sync(WSPIDriver *wspip) {
+
+ while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) {
+ }
+}
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] flags content of the CISR register
+ */
+static void wspi_lld_serve_mdma_interrupt(WSPIDriver *wspip, uint32_t flags) {
+
+ (void)wspip;
+ (void)flags;
+
+ /* DMA errors handling.*/
+#if defined(STM32_WSPI_MDMA_ERROR_HOOK)
+ if ((flags & STM32_MDMA_CISR_TEIF) != 0) {
+ STM32_WSPI_MDMA_ERROR_HOOK(wspip);
+ }
+#endif
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level WSPI driver initialization.
+ *
+ * @notapi
+ */
+void wspi_lld_init(void) {
+
+#if STM32_WSPI_USE_QUADSPI1
+ wspiObjectInit(&WSPID1);
+ WSPID1.qspi = QUADSPI;
+ WSPID1.mdma = NULL;
+#endif
+}
+
+/**
+ * @brief Configures and activates the WSPI peripheral.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_start(WSPIDriver *wspip) {
+
+ /* If in stopped state then full initialization.*/
+ if (wspip->state == WSPI_STOP) {
+#if STM32_WSPI_USE_QUADSPI1
+ if (&WSPID1 == wspip) {
+ wspip->mdma = mdmaChannelAllocI(STM32_WSPI_QUADSPI1_MDMA_CHANNEL,
+ (stm32_mdmaisr_t)wspi_lld_serve_mdma_interrupt,
+ (void *)wspip);
+ osalDbgAssert(wspip->mdma != NULL, "unable to allocate MDMA channel");
+ rccEnableQUADSPI1(true);
+ }
+#endif
+ }
+
+ /* WSPI setup and enable.*/
+ wspip->qspi->DCR = wspip->config->dcr;
+ wspip->qspi->CR = ((STM32_WSPI_QUADSPI1_PRESCALER_VALUE - 1U) << 24U) |
+ QUADSPI_CR_TCIE | QUADSPI_CR_DMAEN | QUADSPI_CR_EN;
+ wspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF |
+ QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF;
+}
+
+/**
+ * @brief Deactivates the WSPI peripheral.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_stop(WSPIDriver *wspip) {
+
+ /* If in ready state then disables the QUADSPI clock.*/
+ if (wspip->state == WSPI_READY) {
+
+ /* WSPI disable.*/
+ wspip->qspi->CR = 0U;
+
+ /* Releasing the DMA.*/
+ mdmaChannelFreeI(wspip->mdma);
+ wspip->mdma = NULL;
+
+ /* Stopping involved clocks.*/
+#if STM32_WSPI_USE_QUADSPI1
+ if (&WSPID1 == wspip) {
+ rccDisableQUADSPI1();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Sends a command without data phase.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ *
+ * @notapi
+ */
+void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp) {
+
+#if STM32_USE_STM32_D1_WORKAROUND == TRUE
+ /* If it is a command without address and alternate phases then the command
+ is sent as an alternate byte, the command phase is suppressed.*/
+ if ((cmdp->cfg & (WSPI_CFG_ADDR_MODE_MASK | WSPI_CFG_ALT_MODE_MASK)) == 0U) {
+ /* The command mode field is copied in the alternate mode field. All
+ other fields are not used in this scenario.*/
+ wspip->qspi->DLR = 0U;
+ wspip->qspi->ABR = cmdp->cmd;
+ wspip->qspi->CCR = (cmdp->cfg & WSPI_CFG_CMD_MODE_MASK) << 6U;
+ return;
+ }
+#endif
+ wspip->qspi->DLR = 0U;
+ wspip->qspi->ABR = cmdp->alt;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->qspi->AR = cmdp->addr;
+ }
+
+ /* Waiting for the previous operation to complete.*/
+ wspi_lld_sync(wspip);
+}
+
+/**
+ * @brief Sends a command with data over the WSPI bus.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[in] n number of bytes to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, const uint8_t *txbuf) {
+ uint32_t ctcr = STM32_MDMA_CTCR_BWM_NON_BUFF | /* Dest. non-cacheable. */
+ STM32_MDMA_CTCR_TRGM_BUFFER | /* Trigger on buffer. */
+ STM32_MDMA_CTCR_TLEN(0U) | /* One byte buffer. */
+ STM32_MDMA_CTCR_DBURST_16 | /* Assuming AXI bus. */
+ STM32_MDMA_CTCR_SBURST_16 | /* Assuming AXI bus. */
+ STM32_MDMA_CTCR_DINCOS_BYTE | /* Byte increment. */
+ STM32_MDMA_CTCR_SINCOS_BYTE | /* Byte increment. */
+ STM32_MDMA_CTCR_DSIZE_BYTE | /* Destination size. */
+ STM32_MDMA_CTCR_SSIZE_BYTE | /* Source size. */
+ STM32_MDMA_CTCR_DINC_FIXED | /* Destination fixed. */
+ STM32_MDMA_CTCR_SINC_INC; /* Source incremented. */
+ uint32_t ccr = STM32_MDMA_CCR_PL(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) |
+ STM32_MDMA_CCR_CTCIE | /* On transfer complete.*/
+ STM32_MDMA_CCR_TCIE; /* On transfer error. */
+
+ /* MDMA initializations.*/
+ mdmaChannelSetSourceX(wspip->mdma, &wspip->qspi->DR);
+ mdmaChannelSetDestinationX(wspip->mdma, txbuf);
+ mdmaChannelSetTransactionSizeX(wspip->mdma, n, 0, 0);
+ mdmaChannelSetModeX(wspip->mdma, ctcr, ccr);
+
+ wspip->qspi->DLR = n - 1;
+ wspip->qspi->ABR = cmdp->alt;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->qspi->AR = cmdp->addr;
+ }
+
+ mdmaChannelEnableX(wspip->mdma);
+}
+
+/**
+ * @brief Sends a command then receives data over the WSPI bus.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[in] n number of bytes to send
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, uint8_t *rxbuf) {
+ uint32_t ctcr = STM32_MDMA_CTCR_BWM_NON_BUFF | /* Dest. non-cacheable. */
+ STM32_MDMA_CTCR_TRGM_BUFFER | /* Trigger on buffer. */
+ STM32_MDMA_CTCR_TLEN(0U) | /* One byte buffer. */
+ STM32_MDMA_CTCR_DBURST_16 | /* Assuming AXI bus. */
+ STM32_MDMA_CTCR_SBURST_16 | /* Assuming AXI bus. */
+ STM32_MDMA_CTCR_DINCOS_BYTE | /* Byte increment. */
+ STM32_MDMA_CTCR_SINCOS_BYTE | /* Byte increment. */
+ STM32_MDMA_CTCR_DSIZE_BYTE | /* Destination size. */
+ STM32_MDMA_CTCR_SSIZE_BYTE | /* Source size. */
+ STM32_MDMA_CTCR_DINC_INC | /* Destination incr. */
+ STM32_MDMA_CTCR_SINC_FIXED; /* Source fixed. */
+ uint32_t ccr = STM32_MDMA_CCR_PL(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) |
+ STM32_MDMA_CCR_CTCIE | /* On transfer complete.*/
+ STM32_MDMA_CCR_TCIE; /* On transfer error. */
+
+ /* MDMA initializations.*/
+ mdmaChannelSetSourceX(wspip->mdma, rxbuf);
+ mdmaChannelSetDestinationX(wspip->mdma, &wspip->qspi->DR);
+ mdmaChannelSetTransactionSizeX(wspip->mdma, n, 0, 0);
+ mdmaChannelSetModeX(wspip->mdma, ctcr, ccr);
+
+ wspip->qspi->DLR = n - 1;
+ wspip->qspi->ABR = cmdp->alt;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg |
+ QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) |
+ QUADSPI_CCR_FMODE_0;
+ if ((cmdp->cfg & WSPI_CFG_ADDR_MODE_MASK) != WSPI_CFG_ADDR_MODE_NONE) {
+ wspip->qspi->AR = cmdp->addr;
+ }
+
+ mdmaChannelEnableX(wspip->mdma);
+}
+
+#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Maps in memory space a WSPI flash device.
+ * @pre The memory flash device must be initialized appropriately
+ * before mapping it in memory space.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ * @param[in] cmdp pointer to the command descriptor
+ * @param[out] addrp pointer to the memory start address of the mapped
+ * flash or @p NULL
+ *
+ * @notapi
+ */
+void wspi_lld_map_flash(WSPIDriver *wspip,
+ const wspi_command_t *cmdp,
+ uint8_t **addrp) {
+
+ /* Disabling the DMA request while in memory mapped mode.*/
+ wspip->qspi->CR &= ~QUADSPI_CR_DMAEN;
+
+ /* Starting memory mapped mode using the passed parameters.*/
+ wspip->qspi->DLR = 0;
+ wspip->qspi->ABR = 0;
+ wspip->qspi->AR = 0;
+ wspip->qspi->CCR = cmdp->cmd | cmdp->cfg |
+ QUADSPI_CCR_DUMMY_CYCLES(cmdp->dummy) |
+ QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0;
+
+ /* Mapped flash absolute base address.*/
+ if (addrp != NULL) {
+ *addrp = (uint8_t *)0x90000000;
+ }
+}
+
+/**
+ * @brief Unmaps from memory space a WSPI flash device.
+ * @post The memory flash device must be re-initialized for normal
+ * commands exchange.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ *
+ * @notapi
+ */
+void wspi_lld_unmap_flash(WSPIDriver *wspip) {
+
+ /* Aborting memory mapped mode.*/
+ wspip->qspi->CR |= QUADSPI_CR_ABORT;
+ while ((wspip->qspi->CR & QUADSPI_CR_ABORT) != 0U) {
+ }
+
+ /* Re-enabling DMA request, we are going back to indirect mode.*/
+ wspip->qspi->CR |= QUADSPI_CR_DMAEN;
+}
+#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] wspip pointer to the @p WSPIDriver object
+ */
+void wspi_lld_serve_interrupt(WSPIDriver *wspip) {
+
+ wspip->qspi->FCR = QUADSPI_FCR_CTEF | QUADSPI_FCR_CTCF |
+ QUADSPI_FCR_CSMF | QUADSPI_FCR_CTOF;
+
+ /* Portable WSPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _wspi_isr_code(wspip);
+
+ mdmaChannelDisableX(wspip->mdma);
+}
+
+#endif /* HAL_USE_WSPI */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h new file mode 100644 index 0000000..cf97200 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/hal_wspi_lld.h @@ -0,0 +1,279 @@ +/*
+ 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 QUADSPIv2/hal_wspi_lld.h
+ * @brief STM32 WSPI subsystem low level driver header.
+ *
+ * @addtogroup WSPI
+ * @{
+ */
+
+#ifndef HAL_WSPI_LLD_H
+#define HAL_WSPI_LLD_H
+
+#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name WSPI implementation capabilities
+ * @{
+ */
+#define WSPI_SUPPORTS_MEMMAP TRUE
+#define WSPI_DEFAULT_CFG_MASKS FALSE
+/** @} */
+
+/**
+ * @name Transfer options
+ * @note The low level driver has the option to override the following
+ * definitions and use its own ones. In must take care to use
+ * the same name for the same function or compatibility is not
+ * ensured.
+ * @note There are the following limitations in this implementation:
+ * - Eight lines are not supported.
+ * - DDR mode is only supported for the whole command, separate
+ * masks are defined but all define the same bit.
+ * - Only 8 bits instructions are supported.
+ * .
+ * @{
+ */
+#define WSPI_CFG_CMD_MODE_MASK (3LU << 8LU)
+#define WSPI_CFG_CMD_MODE_NONE (0LU << 8LU)
+#define WSPI_CFG_CMD_MODE_ONE_LINE (1LU << 8LU)
+#define WSPI_CFG_CMD_MODE_TWO_LINES (2LU << 8LU)
+#define WSPI_CFG_CMD_MODE_FOUR_LINES (3LU << 8LU)
+
+#define WSPI_CFG_CMD_DDR (1LU << 31LU)
+
+#define WSPI_CFG_CMD_SIZE_MASK 0LU
+#define WSPI_CFG_CMD_SIZE_8 0LU
+
+#define WSPI_CFG_ADDR_MODE_MASK (3LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_NONE (0LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_ONE_LINE (1LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_TWO_LINES (2LU << 10LU)
+#define WSPI_CFG_ADDR_MODE_FOUR_LINES (3LU << 10LU)
+
+#define WSPI_CFG_ADDR_DDR (1LU << 31LU)
+
+#define WSPI_CFG_ADDR_SIZE_MASK (3LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_8 (0LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_16 (1LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_24 (2LU << 12LU)
+#define WSPI_CFG_ADDR_SIZE_32 (3LU << 12LU)
+
+#define WSPI_CFG_ALT_MODE_MASK (3LU << 14LU)
+#define WSPI_CFG_ALT_MODE_NONE (0LU << 14LU)
+#define WSPI_CFG_ALT_MODE_ONE_LINE (1LU << 14LU)
+#define WSPI_CFG_ALT_MODE_TWO_LINES (2LU << 14LU)
+#define WSPI_CFG_ALT_MODE_FOUR_LINES (3LU << 14LU)
+
+#define WSPI_CFG_ALT_DDR (1LU << 31LU)
+
+#define WSPI_CFG_ALT_SIZE_MASK (3LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_8 (0LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_16 (1LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_24 (2LU << 16LU)
+#define WSPI_CFG_ALT_SIZE_32 (3LU << 16LU)
+
+#define WSPI_CFG_DATA_MODE_MASK (3LU << 24LU)
+#define WSPI_CFG_DATA_MODE_NONE (0LU << 24LU)
+#define WSPI_CFG_DATA_MODE_ONE_LINE (1LU << 24LU)
+#define WSPI_CFG_DATA_MODE_TWO_LINES (2LU << 24LU)
+#define WSPI_CFG_DATA_MODE_FOUR_LINES (3LU << 24LU)
+
+#define WSPI_CFG_DATA_DDR (1LU << 31LU)
+
+#define WSPI_CFG_SIOO (1LU << 28LU)
+/** @} */
+
+/**
+ * @name Helpers for CCR register.
+ * @{
+ */
+#define QUADSPI_CCR_DUMMY_CYCLES_MASK (0x1FLU << 18LU)
+#define QUADSPI_CCR_DUMMY_CYCLES(n) ((n) << 18LU)
+/** @} */
+
+/**
+ * @name DCR register options
+ * @{
+ */
+#define STM32_DCR_CK_MODE (1U << 0U)
+#define STM32_DCR_CSHT_MASK (7U << 8U)
+#define STM32_DCR_CSHT(n) ((n) << 8U)
+#define STM32_DCR_FSIZE_MASK (31U << 16U)
+#define STM32_DCR_FSIZE(n) ((n) << 16U)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief WSPID1 driver enable switch.
+ * @details If set to @p TRUE the support for QUADSPI1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_WSPI_USE_QUADSPI1) || defined(__DOXYGEN__)
+#define STM32_WSPI_USE_QUADSPI1 FALSE
+#endif
+
+/**
+ * @brief QUADSPI1 prescaler setting.
+ * @note This is the prescaler divider value 1..256. The maximum frequency
+ * varies depending on the STM32 model and operating conditions,
+ * find the details in the data sheet.
+ */
+#if !defined(STM32_WSPI_QUADSPI1_PRESCALER_VALUE) || defined(__DOXYGEN__)
+#define STM32_WSPI_QUADSPI1_PRESCALER_VALUE 1
+#endif
+
+/**
+ * @brief QUADSPI1 MDMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_WSPI_QUADSPI1_MDMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_WSPI_QUADSPI1_MDMA_PRIORITY 1
+#endif
+
+/**
+ * @brief QUADSPI MDMA error hook.
+ */
+#if !defined(STM32_WSPI_MDMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_WSPI_MDMA_ERROR_HOOK(qspip) osalSysHalt("MDMA failure")
+#endif
+
+/**
+ * @brief Enables a workaround for a STM32L476 QUADSPI errata.
+ * @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an
+ * input when the command is sent in dual or quad SPI mode".
+ * This workaround makes commands without address or data phases
+ * to be sent as alternate bytes.
+ */
+#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__)
+#define STM32_USE_STM32_D1_WORKAROUND TRUE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_QUADSPI1)
+#define STM32_HAS_QUADSPI1 FALSE
+#endif
+
+#if STM32_WSPI_USE_QUADSPI1 && !STM32_HAS_QUADSPI1
+#error "QUADSPI1 not present in the selected device"
+#endif
+
+#if !STM32_WSPI_USE_QUADSPI1
+#error "WSPI driver activated but no QUADSPI peripheral assigned"
+#endif
+
+/* MDMA-related checks.*/
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !STM32_MDMA_IS_VALID_PRIORITY(STM32_WSPI_QUADSPI1_MDMA_PRIORITY)
+#error "Invalid MDMA priority assigned to QUADSPI1"
+#endif
+
+/* Checks on prescaler setting.*/
+#if (STM32_WSPI_QUADSPI1_PRESCALER_VALUE < 1) || \
+ (STM32_WSPI_QUADSPI1_PRESCALER_VALUE > 256)
+#error "STM32_WSPI_QUADSPI1_PRESCALER_VALUE not within 1..256"
+#endif
+
+/* Check on the presence of the DMA channels settings in mcuconf.h.*/
+#if STM32_WSPI_USE_QUADSPI1 && !defined(STM32_WSPI_QUADSPI1_MDMA_CHANNEL)
+#error "QUADSPI1 MDMA channel not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_WSPI_USE_QUADSPI1 && \
+ !STM32_MDMA_IS_VALID_CHANNEL(STM32_WSPI_QUADSPI1_MDMA_CHANNEL)
+#error "invalid MDMA channel associated to QUADSPI1"
+#endif
+
+#if !defined(STM32_MDMA_REQUIRED)
+#define STM32_MDMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the WSPI configuration structure.
+ */
+#define wspi_lld_config_fields \
+ /* DCR register initialization data.*/ \
+ uint32_t dcr
+
+/**
+ * @brief Low level fields of the WSPI driver structure.
+ */
+#define wspi_lld_driver_fields \
+ /* Pointer to the QUADSPIx registers block.*/ \
+ QUADSPI_TypeDef *qspi; \
+ /* QUADSPI MDMA channel.*/ \
+ const stm32_mdma_channel_t *mdma
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if (STM32_WSPI_USE_QUADSPI1 == TRUE) && !defined(__DOXYGEN__)
+extern WSPIDriver WSPID1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void wspi_lld_init(void);
+ void wspi_lld_start(WSPIDriver *wspip);
+ void wspi_lld_stop(WSPIDriver *wspip);
+ void wspi_lld_command(WSPIDriver *wspip, const wspi_command_t *cmdp);
+ void wspi_lld_send(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, const uint8_t *txbuf);
+ void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
+ size_t n, uint8_t *rxbuf);
+#if WSPI_SUPPORTS_MEMMAP == TRUE
+ void wspi_lld_map_flash(WSPIDriver *wspip,
+ const wspi_command_t *cmdp,
+ uint8_t **addrp);
+ void wspi_lld_unmap_flash(WSPIDriver *wspip);
+#endif
+ void wspi_lld_serve_interrupt(WSPIDriver *wspip);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_WSPI */
+
+#endif /* HAL_WSPI_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc new file mode 100644 index 0000000..371bf77 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/QUADSPIv2/stm32_quadspi1.inc @@ -0,0 +1,110 @@ +/* + 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 QUADSPIv2/stm32_quadspi1.inc + * @brief Shared QUADSPI1 handler. + * + * @addtogroup STM32_QUADSPI1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_QUADSPI1) +#error "STM32_HAS_QUADSPI1 not defined in registry" +#endif + +#if STM32_HAS_QUADSPI1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_QUADSPI1_PRIORITY) +#error "STM32_IRQ_QUADSPI1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_QUADSPI1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_QUADSPI1_PRIORITY" +#endif + +#endif /* STM32_HAS_QUADSPI1 */ + +/* Other checks.*/ +#if (HAL_USE_WSPI && STM32_WSPI_USE_QUADSPI1) +#define STM32_QUADSPI1_IS_USED TRUE +#else +#define STM32_QUADSPI1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void quadspi1_irq_init(void) { +#if STM32_QUADSPI1_IS_USED + nvicEnableVector(STM32_QUADSPI1_NUMBER, STM32_IRQ_QUADSPI1_PRIORITY); +#endif +} + +static inline void quadspi1_irq_deinit(void) { +#if STM32_QUADSPI1_IS_USED + nvicDisableVector(STM32_QUADSPI1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_QUADSPI1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief QUADSPI1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_QUADSPI1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_WSPI +#if STM32_WSPI_USE_QUADSPI1 + wspi_lld_serve_interrupt(&WSPID1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk new file mode 100644 index 0000000..3c90500 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_TRNG TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c new file mode 100644 index 0000000..c81e433 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.c @@ -0,0 +1,179 @@ +/*
+ 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 hal_trng_lld.c
+ * @brief STM32 TRNG subsystem low level driver source.
+ *
+ * @addtogroup TRNG
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief TRNGD1 driver identifier.
+ */
+#if (STM32_TRNG_USE_RNG1 == TRUE) || defined(__DOXYGEN__)
+TRNGDriver TRNGD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const TRNGConfig default_cfg = {.cr = 0};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level TRNG driver initialization.
+ *
+ * @notapi
+ */
+void trng_lld_init(void) {
+
+#if STM32_TRNG_USE_RNG1 == TRUE
+ /* Driver initialization.*/
+ trngObjectInit(&TRNGD1);
+ TRNGD1.rng = RNG;
+#endif
+}
+
+/**
+ * @brief Configures and activates the TRNG peripheral.
+ *
+ * @param[in] trngp pointer to the @p TRNGDriver object
+ *
+ * @notapi
+ */
+void trng_lld_start(TRNGDriver *trngp) {
+
+ /* There is no real configuration but setting up a valid pointer anyway.*/
+ if (trngp->config == NULL) {
+ trngp->config = &default_cfg;
+ }
+
+ if (trngp->state == TRNG_STOP) {
+ /* Enables the peripheral.*/
+#if STM32_TRNG_USE_RNG1 == TRUE
+ if (&TRNGD1 == trngp) {
+ rccEnableRNG(false);
+ }
+#endif
+ }
+ /* Configures the peripheral.*/
+ trngp->rng->CR |= RNG_CR_RNGEN;
+}
+
+/**
+ * @brief Deactivates the TRNG peripheral.
+ *
+ * @param[in] trngp pointer to the @p TRNGDriver object
+ *
+ * @notapi
+ */
+void trng_lld_stop(TRNGDriver *trngp) {
+
+ if (trngp->state == TRNG_READY) {
+ /* Resets the peripheral.*/
+ trngp->rng->CR &= ~RNG_CR_RNGEN;
+
+ /* Disables the peripheral.*/
+#if STM32_TRNG_USE_RNG1 == TRUE
+ if (&TRNGD1 == trngp) {
+ rccDisableRNG();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief True random numbers generator.
+ * @note The function is blocking and likely performs polled waiting
+ * inside the low level implementation.
+ *
+ * @param[in] trngp pointer to the @p TRNGDriver object
+ * @param[in] size size of output buffer
+ * @param[out] out output buffer
+ * @return The operation status.
+ * @retval false if a random number has been generated.
+ * @retval true if an HW error occurred.
+ *
+ * @api
+ */
+bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out) {
+
+ while (true) {
+ uint32_t r, tmo;
+ size_t i;
+
+ /* Waiting for error conditions to be cleared.*/
+ tmo = STM32_TRNG_ERROR_CLEAR_ATTEMPTS;
+ while ((tmo > 0) && ((trngp->rng->SR & (RNG_SR_CECS | RNG_SR_SECS)) != 0)) {
+ tmo--;
+ if (tmo == 0) {
+ return true;
+ }
+ }
+
+ /* Waiting for a random number in data register.*/
+ tmo = STM32_DATA_FETCH_ATTEMPTS;
+ while ((tmo > 0) && ((trngp->rng->SR & RNG_SR_DRDY) == 0)) {
+ tmo--;
+ if (tmo == 0) {
+ return true;
+ }
+ }
+
+ /* Getting the generated random number.*/
+ r = trngp->rng->DR;
+
+ /* Writing in the output buffer.*/
+ for (i = 0; i < sizeof (uint32_t) / sizeof (uint8_t); i++) {
+ *out++ = (uint8_t)r;
+ r = r >> 8;
+ size--;
+ if (size == 0) {
+ return false;
+ }
+ }
+ }
+}
+
+#endif /* HAL_USE_TRNG == TRUE */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h new file mode 100644 index 0000000..2a1e9ba --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/hal_trng_lld.h @@ -0,0 +1,141 @@ +/*
+ 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 hal_trng_lld.h
+ * @brief STM32 TRNG subsystem low level driver header.
+ *
+ * @addtogroup TRNG
+ * @{
+ */
+
+#ifndef HAL_TRNG_LLD_H
+#define HAL_TRNG_LLD_H
+
+#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name STM32 configuration options
+ * @{
+ */
+/**
+ * @brief TRNGD1 driver enable switch.
+ * @details If set to @p TRUE the support for TRNGD1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_TRNG_USE_RNG1) || defined(__DOXYGEN__)
+#define STM32_TRNG_USE_RNG1 FALSE
+#endif
+
+/**
+ * @brief TRNGD1 error clear timeout counter.
+ * @details Number of status register fetches before failing.
+ */
+#if !defined(STM32_TRNG_ERROR_CLEAR_ATTEMPTS) || defined(__DOXYGEN__)
+#define STM32_TRNG_ERROR_CLEAR_ATTEMPTS 1000
+#endif
+
+/**
+ * @brief TRNGD1 data available timeout counter.
+ * @details Number of status register fetches before failing.
+ */
+#if !defined(STM32_DATA_FETCH_ATTEMPTS) || defined(__DOXYGEN__)
+#define STM32_DATA_FETCH_ATTEMPTS 1000
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_RNG1)
+#define STM32_HAS_RNG1 FALSE
+#endif
+
+#if STM32_TRNG_USE_RNG1 && !STM32_HAS_RNG1
+#error "RNG1 not present in the selected device"
+#endif
+
+#if !STM32_TRNG_USE_RNG1
+#error "TRNG driver activated but no RNG peripheral assigned"
+#endif
+
+#if !defined(STM32_RNGCLK)
+#error "STM32_RNGCLK not defined in this HAL"
+#endif
+
+#if ((STM32_RNGCLK < 47000000) || (STM32_RNGCLK > 49000000)) && \
+ ((STM32_RNGCLK < 3500000) || (STM32_RNGCLK > 4500000))
+#if !defined(STM32_DISABLE_RNG_CLOCK_CHECK)
+#error "STM32_RNGCLK is not within a tested clock range"
+#error "define STM32_DISABLE_RNG_CLOCK_CHECK to override this check"
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the TRNG configuration structure.
+ */
+#define trng_lld_config_fields \
+ /* CR register initialization value.*/ \
+ uint32_t cr
+
+/**
+ * @brief Low level fields of the TRNG driver structure.
+ */
+#define trng_lld_driver_fields \
+ /* Pointer to the RNG registers block.*/ \
+ RNG_TypeDef *rng
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if (STM32_TRNG_USE_RNG1 == TRUE) && !defined(__DOXYGEN__)
+extern TRNGDriver TRNGD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void trng_lld_init(void);
+ void trng_lld_start(TRNGDriver *trngp);
+ void trng_lld_stop(TRNGDriver *trngp);
+ bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_TRNG == TRUE */
+
+#endif /* HAL_TRNG_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt new file mode 100644 index 0000000..8e0c8e5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RNGv1/notes.txt @@ -0,0 +1,10 @@ +STM32 RNGv1 driver.
+
+Driver capability:
+
+- Supports the STM32 TRNGv1 found on STM32L4 and STM32L4+ families.
+
+The file registry must export:
+
+STM32_HAS_RNG1 - RNG presence flag.
+
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk new file mode 100644 index 0000000..972b475 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c new file mode 100644 index 0000000..248a9c3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.c @@ -0,0 +1,447 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file RTCv1/hal_rtc_lld.c
+ * @brief STM32 RTC subsystem low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC driver identifier.
+ */
+RTCDriver RTCD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Wait for synchronization of RTC registers with APB1 bus.
+ * @details This function must be invoked before trying to read RTC registers
+ * in the backup domain: DIV, CNT, ALR. CR registers can always
+ * be read.
+ *
+ * @notapi
+ */
+static void rtc_apb1_sync(void) {
+
+ while ((RTC->CRL & RTC_CRL_RSF) == 0)
+ ;
+}
+
+/**
+ * @brief Wait for for previous write operation complete.
+ * @details This function must be invoked before writing to any RTC registers
+ *
+ * @notapi
+ */
+static void rtc_wait_write_completed(void) {
+
+ while ((RTC->CRL & RTC_CRL_RTOFF) == 0)
+ ;
+}
+
+/**
+ * @brief Acquires write access to RTC registers.
+ * @details Before writing to the backup domain RTC registers the previous
+ * write operation must be completed. Use this function before
+ * writing to PRL, CNT, ALR registers.
+ *
+ * @notapi
+ */
+static void rtc_acquire_access(void) {
+
+ rtc_wait_write_completed();
+ RTC->CRL |= RTC_CRL_CNF;
+}
+
+/**
+ * @brief Releases write access to RTC registers.
+ *
+ * @notapi
+ */
+static void rtc_release_access(void) {
+
+ RTC->CRL &= ~RTC_CRL_CNF;
+}
+
+/**
+ * @brief Converts time from timespec to seconds counter.
+ *
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ * @return the TR register encoding.
+ *
+ * @notapi
+ */
+static time_t rtc_encode(const RTCDateTime *timespec) {
+ struct tm tim;
+
+ rtcConvertDateTimeToStructTm(timespec, &tim, NULL);
+ return mktime(&tim);
+}
+
+/**
+ * @brief Converts time from seconds/milliseconds to timespec.
+ *
+ * @param[in] tv_sec seconds value
+ * @param[in] tv_msec milliseconds value
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+static void rtc_decode(uint32_t tv_sec,
+ uint32_t tv_msec,
+ RTCDateTime *timespec) {
+ struct tm tim;
+ struct tm *t;
+ const time_t time = (const time_t)tv_sec; /* Could be 64 bits.*/
+
+ /* If the conversion is successful the function returns a pointer
+ to the object the result was written into.*/
+#if defined(__GNUC__) || defined(__CC_ARM)
+ t = localtime_r(&time, &tim);
+ osalDbgAssert(t != NULL, "conversion failed");
+#else
+ t = localtime(&time);
+ memcpy(&tim, t, sizeof(struct tm));
+#endif
+
+ rtcConvertStructTmToDateTime(&tim, tv_msec, timespec);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC1_HANDLER) {
+ uint16_t flags;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Code hits this wait only when AHB1 bus was previously powered off by any
+ reason (standby, reset, etc). In other cases there is no waiting.*/
+ rtc_apb1_sync();
+
+ /* Mask of all enabled and pending sources.*/
+ flags = RTCD1.rtc->CRH & RTCD1.rtc->CRL;
+ RTCD1.rtc->CRL &= ~(RTC_CRL_SECF | RTC_CRL_ALRF | RTC_CRL_OWF);
+
+ if (flags & RTC_CRL_SECF)
+ RTCD1.callback(&RTCD1, RTC_EVENT_SECOND);
+
+ if (flags & RTC_CRL_ALRF)
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM);
+
+ if (flags & RTC_CRL_OWF)
+ RTCD1.callback(&RTCD1, RTC_EVENT_OVERFLOW);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Load value of RTCCLK to prescaler registers.
+ * @note The pre-scaler must not be set on every reset as RTC clock
+ * counts are lost when it is set.
+ * @note This function designed to be called from
+ * hal_lld_backup_domain_init(). Because there is only place
+ * where possible to detect BKP domain reset event reliably.
+ *
+ * @notapi
+ */
+void rtc_lld_set_prescaler(void) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ rtc_acquire_access();
+ RTC->PRLH = (uint16_t)((STM32_RTCCLK - 1) >> 16) & 0x000F;
+ RTC->PRLL = (uint16_t)(((STM32_RTCCLK - 1)) & 0xFFFF);
+ rtc_release_access();
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Initialize RTC.
+ *
+ * @notapi
+ */
+void rtc_lld_init(void) {
+
+ /* RTC object initialization.*/
+ rtcObjectInit(&RTCD1);
+
+ /* RTC pointer initialization.*/
+ RTCD1.rtc = RTC;
+
+ /* RSF bit must be cleared by software after an APB1 reset or an APB1 clock
+ stop. Otherwise its value will not be actual. */
+ RTCD1.rtc->CRL &= ~RTC_CRL_RSF;
+
+ /* Required because access to PRL.*/
+ rtc_apb1_sync();
+
+ /* All interrupts initially disabled.*/
+ rtc_wait_write_completed();
+ RTCD1.rtc->CRH = 0;
+
+ /* Callback initially disabled.*/
+ RTCD1.callback = NULL;
+
+ /* IRQ vector permanently assigned to this driver.*/
+ nvicEnableVector(STM32_RTC1_NUMBER, STM32_RTC_IRQ_PRIORITY);
+}
+
+/**
+ * @brief Set current time.
+ * @note Fractional part will be silently ignored. There is no possibility
+ * to change it on STM32F1xx platform.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) {
+ time_t tv_sec = rtc_encode(timespec);
+
+ rtcSTM32SetSec(rtcp, tv_sec);
+}
+
+/**
+ * @brief Get current time.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) {
+ uint32_t tv_sec, tv_msec;
+
+ rtcSTM32GetSecMsec(rtcp, &tv_sec, &tv_msec);
+ rtc_decode(tv_sec, tv_msec, timespec);
+}
+
+/**
+ * @brief Set alarm time.
+ *
+ * @note Default value after BKP domain reset is 0xFFFFFFFF
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[in] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm_number,
+ const RTCAlarm *alarmspec) {
+ syssts_t sts;
+ (void)alarm_number;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ rtc_acquire_access();
+ if (alarmspec != NULL) {
+ rtcp->rtc->ALRH = (uint16_t)(alarmspec->tv_sec >> 16);
+ rtcp->rtc->ALRL = (uint16_t)(alarmspec->tv_sec & 0xFFFF);
+ }
+ else {
+ rtcp->rtc->ALRH = 0;
+ rtcp->rtc->ALRL = 0;
+ }
+ rtc_release_access();
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Get current alarm.
+ * @note If an alarm has not been set then the returned alarm specification
+ * is not meaningful.
+ * @note The function can be called from any context.
+ * @note Default value after BKP domain reset is 0xFFFFFFFF.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[out] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm_number,
+ RTCAlarm *alarmspec) {
+ syssts_t sts;
+ (void)alarm_number;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ /* Required because access to ALR.*/
+ rtc_apb1_sync();
+
+ alarmspec->tv_sec = ((rtcp->rtc->ALRH << 16) + rtcp->rtc->ALRL);
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Enables or disables RTC callbacks.
+ * @details This function enables or disables callbacks, use a @p NULL pointer
+ * in order to disable a callback.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] callback callback function pointer or @p NULL
+ *
+ * @notapi
+ */
+void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ if (callback != NULL) {
+
+ /* IRQ sources enabled only after setting up the callback.*/
+ rtcp->callback = callback;
+
+ rtc_wait_write_completed();
+ rtcp->rtc->CRL &= ~(RTC_CRL_OWF | RTC_CRL_ALRF | RTC_CRL_SECF);
+ rtcp->rtc->CRH = RTC_CRH_OWIE | RTC_CRH_ALRIE | RTC_CRH_SECIE;
+ }
+ else {
+ rtc_wait_write_completed();
+ rtcp->rtc->CRH = 0;
+
+ /* Callback set to NULL only after disabling the IRQ sources.*/
+ rtcp->callback = NULL;
+ }
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Get seconds and (optionally) milliseconds from RTC.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] tv_sec pointer to seconds value
+ * @param[out] tv_msec pointer to milliseconds value, set it
+ * to @p NULL if not needed
+ *
+ * @api
+ */
+void rtcSTM32GetSecMsec(RTCDriver *rtcp, uint32_t *tv_sec, uint32_t *tv_msec) {
+ uint32_t time_frac;
+ syssts_t sts;
+
+ osalDbgCheck((NULL != tv_sec) && (NULL != rtcp));
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ /* Required because access to CNT and DIV.*/
+ rtc_apb1_sync();
+
+ /* wait for previous write accesses to complete.*/
+ rtc_wait_write_completed();
+
+ /* Loops until two consecutive read returning the same value.*/
+ do {
+ *tv_sec = ((uint32_t)(rtcp->rtc->CNTH) << 16) + rtcp->rtc->CNTL;
+ time_frac = (((uint32_t)rtcp->rtc->DIVH) << 16) + (uint32_t)rtcp->rtc->DIVL;
+ } while ((*tv_sec) != (((uint32_t)(rtcp->rtc->CNTH) << 16) + rtcp->rtc->CNTL));
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+
+ if (NULL != tv_msec)
+ *tv_msec = (((uint32_t)STM32_RTCCLK - 1 - time_frac) * 1000) / STM32_RTCCLK;
+}
+
+/**
+ * @brief Set seconds in RTC.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] tv_sec seconds value
+ *
+ * @api
+ */
+void rtcSTM32SetSec(RTCDriver *rtcp, uint32_t tv_sec) {
+ syssts_t sts;
+
+ osalDbgCheck(NULL != rtcp);
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ rtc_acquire_access();
+ rtcp->rtc->CNTH = (uint16_t)(tv_sec >> 16);
+ rtcp->rtc->CNTL = (uint16_t)(tv_sec & 0xFFFF);
+ rtc_release_access();
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+#endif /* HAL_USE_RTC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h new file mode 100644 index 0000000..0926315 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv1/hal_rtc_lld.h @@ -0,0 +1,152 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file RTCv1/hal_rtc_lld.h
+ * @brief STM32 RTC subsystem low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#ifndef HAL_RTC_LLD_H
+#define HAL_RTC_LLD_H
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Implementation capabilities
+ */
+/**
+ * @brief This RTC implementation supports callbacks.
+ */
+#define RTC_SUPPORTS_CALLBACKS TRUE
+
+/**
+ * @brief One alarm comparator available.
+ */
+#define RTC_ALARMS 1
+
+/**
+ * @brief Presence of a local persistent storage.
+ */
+#define RTC_HAS_STORAGE FALSE
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/*
+ * RTC driver system settings.
+ */
+#define STM32_RTC_IRQ_PRIORITY 15
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if HAL_USE_RTC && !STM32_HAS_RTC
+#error "RTC not present in the selected device"
+#endif
+
+#if STM32_RTCCLK == 0
+#error "RTC clock not enabled"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of an RTC event.
+ */
+typedef enum {
+ RTC_EVENT_SECOND = 0, /** Triggered every second. */
+ RTC_EVENT_ALARM = 1, /** Triggered on alarm. */
+ RTC_EVENT_OVERFLOW = 2 /** Triggered on counter overflow. */
+} rtcevent_t;
+
+/**
+ * @brief Type of a generic RTC callback.
+ */
+typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
+
+/**
+ * @brief Type of a structure representing an RTC alarm time stamp.
+ */
+typedef struct hal_rtc_alarm {
+ /**
+ * @brief Seconds since UNIX epoch.
+ */
+ uint32_t tv_sec;
+} RTCAlarm;
+
+/**
+ * @brief Implementation-specific @p RTCDriver fields.
+ */
+#define rtc_lld_driver_fields \
+ /* Pointer to the RTC registers block.*/ \
+ RTC_TypeDef *rtc; \
+ /* Callback pointer.*/ \
+ rtccb_t callback
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void rtc_lld_set_prescaler(void);
+ void rtc_lld_init(void);
+ void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec);
+ void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec);
+ void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm_number,
+ const RTCAlarm *alarmspec);
+ void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm_number,
+ RTCAlarm *alarmspec);
+ void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
+ void rtcSTM32GetSecMsec(RTCDriver *rtcp, uint32_t *tv_sec, uint32_t *tv_msec);
+ void rtcSTM32SetSec(RTCDriver *rtcp, uint32_t tv_sec);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_RTC */
+
+#endif /* HAL_RTC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk new file mode 100644 index 0000000..25ef11d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c new file mode 100644 index 0000000..aa8bb5e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.c @@ -0,0 +1,843 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file RTCv2/hal_rtc_lld.c
+ * @brief STM32 RTC low level driver.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define RTC_TR_PM_OFFSET 22
+#define RTC_TR_HT_OFFSET 20
+#define RTC_TR_HU_OFFSET 16
+#define RTC_TR_MNT_OFFSET 12
+#define RTC_TR_MNU_OFFSET 8
+#define RTC_TR_ST_OFFSET 4
+#define RTC_TR_SU_OFFSET 0
+
+#define RTC_DR_YT_OFFSET 20
+#define RTC_DR_YU_OFFSET 16
+#define RTC_DR_WDU_OFFSET 13
+#define RTC_DR_MT_OFFSET 12
+#define RTC_DR_MU_OFFSET 8
+#define RTC_DR_DT_OFFSET 4
+#define RTC_DR_DU_OFFSET 0
+
+#define RTC_CR_BKP_OFFSET 18
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC driver identifier.
+ */
+RTCDriver RTCD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Beginning of configuration procedure.
+ *
+ * @notapi
+ */
+static void rtc_enter_init(void) {
+
+ RTCD1.rtc->ISR |= RTC_ISR_INIT;
+ while ((RTCD1.rtc->ISR & RTC_ISR_INITF) == 0)
+ ;
+}
+
+/**
+ * @brief Finalizing of configuration procedure.
+ *
+ * @notapi
+ */
+static inline void rtc_exit_init(void) {
+
+ RTCD1.rtc->ISR &= ~RTC_ISR_INIT;
+}
+
+/**
+ * @brief Converts time from TR register encoding to timespec.
+ *
+ * @param[in] tr TR register value
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+static void rtc_decode_time(uint32_t tr, RTCDateTime *timespec) {
+ uint32_t n;
+
+ n = ((tr >> RTC_TR_HT_OFFSET) & 3) * 36000000;
+ n += ((tr >> RTC_TR_HU_OFFSET) & 15) * 3600000;
+ n += ((tr >> RTC_TR_MNT_OFFSET) & 7) * 600000;
+ n += ((tr >> RTC_TR_MNU_OFFSET) & 15) * 60000;
+ n += ((tr >> RTC_TR_ST_OFFSET) & 7) * 10000;
+ n += ((tr >> RTC_TR_SU_OFFSET) & 15) * 1000;
+ timespec->millisecond = n;
+}
+
+/**
+ * @brief Converts date from DR register encoding to timespec.
+ *
+ * @param[in] dr DR register value
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+static void rtc_decode_date(uint32_t dr, RTCDateTime *timespec) {
+
+ timespec->year = (((dr >> RTC_DR_YT_OFFSET) & 15) * 10) +
+ ((dr >> RTC_DR_YU_OFFSET) & 15);
+ timespec->month = (((dr >> RTC_TR_MNT_OFFSET) & 1) * 10) +
+ ((dr >> RTC_TR_MNU_OFFSET) & 15);
+ timespec->day = (((dr >> RTC_DR_DT_OFFSET) & 3) * 10) +
+ ((dr >> RTC_DR_DU_OFFSET) & 15);
+ timespec->dayofweek = (dr >> RTC_DR_WDU_OFFSET) & 7;
+}
+
+/**
+ * @brief Converts time from timespec to TR register encoding.
+ *
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ * @return the TR register encoding.
+ *
+ * @notapi
+ */
+static uint32_t rtc_encode_time(const RTCDateTime *timespec) {
+ uint32_t n, tr = 0;
+
+ /* Subseconds cannot be set.*/
+ n = timespec->millisecond / 1000;
+
+ /* Seconds conversion.*/
+ tr = tr | ((n % 10) << RTC_TR_SU_OFFSET);
+ n /= 10;
+ tr = tr | ((n % 6) << RTC_TR_ST_OFFSET);
+ n /= 6;
+
+ /* Minutes conversion.*/
+ tr = tr | ((n % 10) << RTC_TR_MNU_OFFSET);
+ n /= 10;
+ tr = tr | ((n % 6) << RTC_TR_MNT_OFFSET);
+ n /= 6;
+
+ /* Hours conversion.*/
+ tr = tr | ((n % 10) << RTC_TR_HU_OFFSET);
+ n /= 10;
+ tr = tr | (n << RTC_TR_HT_OFFSET);
+
+ return tr;
+}
+
+/**
+ * @brief Converts a date from timespec to DR register encoding.
+ *
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ * @return the DR register encoding.
+ *
+ * @notapi
+ */
+static uint32_t rtc_encode_date(const RTCDateTime *timespec) {
+ uint32_t n, dr = 0;
+
+ /* Year conversion. Note, only years last two digits are considered.*/
+ n = timespec->year;
+ dr = dr | ((n % 10) << RTC_DR_YU_OFFSET);
+ n /= 10;
+ dr = dr | ((n % 10) << RTC_DR_YT_OFFSET);
+
+ /* Months conversion.*/
+ n = timespec->month;
+ dr = dr | ((n % 10) << RTC_DR_MU_OFFSET);
+ n /= 10;
+ dr = dr | ((n % 10) << RTC_DR_MT_OFFSET);
+
+ /* Days conversion.*/
+ n = timespec->day;
+ dr = dr | ((n % 10) << RTC_DR_DU_OFFSET);
+ n /= 10;
+ dr = dr | ((n % 10) << RTC_DR_DT_OFFSET);
+
+ /* Days of week conversion.*/
+ dr = dr | (timespec->dayofweek << RTC_DR_WDU_OFFSET);
+
+ return dr;
+}
+
+#if RTC_HAS_STORAGE == TRUE
+static size_t _getsize(void *instance) {
+
+ (void)instance;
+
+ return (size_t)STM32_RTC_STORAGE_SIZE;
+}
+
+static ps_error_t _read(void *instance, ps_offset_t offset,
+ size_t n, uint8_t *rp) {
+ volatile uint32_t *bkpr = &((RTCDriver *)instance)->rtc->BKP0R;
+ unsigned i;
+
+ chDbgCheck((instance != NULL) && (rp != NULL));
+ chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE));
+ chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) &&
+ (offset + n <= STM32_RTC_STORAGE_SIZE));
+
+ for (i = 0; i < (unsigned)n; i++) {
+ unsigned index = ((unsigned)offset + i) / sizeof (uint32_t);
+ unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t);
+ *rp++ = (uint8_t)(bkpr[index] >> (shift * 8U));
+ }
+
+ return PS_NO_ERROR;
+}
+
+static ps_error_t _write(void *instance, ps_offset_t offset,
+ size_t n, const uint8_t *wp) {
+ volatile uint32_t *bkpr = &((RTCDriver *)instance)->rtc->BKP0R;
+ unsigned i;
+
+ chDbgCheck((instance != NULL) && (wp != NULL));
+ chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE));
+ chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) &&
+ (offset + n <= STM32_RTC_STORAGE_SIZE));
+
+ for (i = 0; i < (unsigned)n; i++) {
+ unsigned index = ((unsigned)offset + i) / sizeof (uint32_t);
+ unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t);
+ uint32_t regval = bkpr[index];
+ regval &= ~(0xFFU << (shift * 8U));
+ regval |= (uint32_t)*wp++ << (shift * 8U);
+ bkpr[index] = regval;
+ }
+
+ return PS_NO_ERROR;
+}
+
+/**
+ * @brief VMT for the RTC storage file interface.
+ */
+struct RTCDriverVMT _rtc_lld_vmt = {
+ (size_t)0,
+ _getsize, _read, _write
+};
+#endif /* RTC_HAS_STORAGE == TRUE */
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if defined(STM32_RTC_COMMON_HANDLER)
+#if !defined(STM32_RTC_SUPPRESS_COMMON_ISR)
+/**
+ * @brief RTC common interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_COMMON_HANDLER) {
+ uint32_t isr, clear;
+
+ OSAL_IRQ_PROLOGUE();
+
+ clear = (0U
+ | RTC_ISR_TSF
+ | RTC_ISR_TSOVF
+#if defined(RTC_ISR_TAMP1F)
+ | RTC_ISR_TAMP1F
+#endif
+#if defined(RTC_ISR_TAMP2F)
+ | RTC_ISR_TAMP2F
+#endif
+#if defined(RTC_ISR_TAMP3F)
+ | RTC_ISR_TAMP3F
+#endif
+#if defined(RTC_ISR_WUTF)
+ | RTC_ISR_WUTF
+#endif
+#if defined(RTC_ISR_ALRAF)
+ | RTC_ISR_ALRAF
+#endif
+#if defined(RTC_ISR_ALRBF)
+ | RTC_ISR_ALRBF
+#endif
+ );
+
+ isr = RTCD1.rtc->ISR;
+ RTCD1.rtc->ISR = isr & ~clear;
+
+ extiClearGroup1(EXTI_MASK1(STM32_RTC_ALARM_EXTI) |
+ EXTI_MASK1(STM32_RTC_TAMP_STAMP_EXTI) |
+ EXTI_MASK1(STM32_RTC_WKUP_EXTI));
+
+ if (RTCD1.callback != NULL) {
+ uint32_t cr = RTCD1.rtc->CR;
+ uint32_t tcr;
+
+#if defined(RTC_ISR_WUTF)
+ if (((cr & RTC_CR_WUTIE) != 0U) && ((isr & RTC_ISR_WUTF) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP);
+ }
+#endif
+
+#if defined(RTC_ISR_ALRAF)
+ if (((cr & RTC_CR_ALRAIE) != 0U) && ((isr & RTC_ISR_ALRAF) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A);
+ }
+#endif
+#if defined(RTC_ISR_ALRBF)
+ if (((cr & RTC_CR_ALRBIE) != 0U) && ((isr & RTC_ISR_ALRBF) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B);
+ }
+#endif
+
+ if ((cr & RTC_CR_TSIE) != 0U) {
+ if ((isr & RTC_ISR_TSF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TS);
+ }
+ if ((isr & RTC_ISR_TSOVF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF);
+ }
+ }
+
+ /* This part is different depending on if the RTC has a TAMPCR or TAFCR
+ register.*/
+#if defined(RTC_TAFCR_TAMP1E)
+ tcr = RTCD1.rtc->TAFCR;
+ if ((tcr & RTC_TAFCR_TAMPIE) != 0U) {
+#if defined(RTC_ISR_TAMP1F)
+ if ((isr & RTC_ISR_TAMP1F) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1);
+ }
+#endif
+#if defined(RTC_ISR_TAMP2F)
+ if ((isr & RTC_ISR_TAMP2F) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2);
+ }
+#endif
+ }
+
+#else /* !defined(RTC_TAFCR_TAMP1E) */
+ tcr = RTCD1.rtc->TAMPCR;
+#if defined(RTC_ISR_TAMP1F)
+ if (((tcr & RTC_TAMPCR_TAMP1IE) != 0U) &&
+ ((isr & RTC_ISR_TAMP1F) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1);
+ }
+#endif
+#if defined(RTC_ISR_TAMP2F)
+ if (((tcr & RTC_TAMPCR_TAMP2IE) != 0U) &&
+ ((isr & RTC_ISR_TAMP2F) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2);
+ }
+#endif
+#if defined(RTC_ISR_TAMP3F)
+ if (((tcr & RTC_TAMPCR_TAMP3IE) != 0U) &&
+ ((isr & RTC_ISR_TAMP3F) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3);
+ }
+#endif
+#endif /* !defined(RTC_TAFCR_TAMP1E) */
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_RTC_SUPPRESS_COMMON_ISR) */
+
+#elif defined(STM32_RTC_TAMP_STAMP_HANDLER) && \
+ defined(STM32_RTC_WKUP_HANDLER) && \
+ defined(STM32_RTC_ALARM_HANDLER)
+/**
+ * @brief RTC TAMP/STAMP interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_TAMP_STAMP_HANDLER) {
+ uint32_t isr, clear;
+
+ OSAL_IRQ_PROLOGUE();
+
+ clear = (0U
+ | RTC_ISR_TSF
+ | RTC_ISR_TSOVF
+#if defined(RTC_ISR_TAMP1F)
+ | RTC_ISR_TAMP1F
+#endif
+#if defined(RTC_ISR_TAMP2F)
+ | RTC_ISR_TAMP2F
+#endif
+#if defined(RTC_ISR_TAMP3F)
+ | RTC_ISR_TAMP3F
+#endif
+ );
+
+ isr = RTCD1.rtc->ISR;
+ RTCD1.rtc->ISR = isr & ~clear;
+
+ extiClearGroup1(EXTI_MASK1(STM32_RTC_TAMP_STAMP_EXTI));
+
+ if (RTCD1.callback != NULL) {
+ uint32_t cr, tcr;
+
+ cr = RTCD1.rtc->CR;
+ if ((cr & RTC_CR_TSIE) != 0U) {
+ if ((isr & RTC_ISR_TSF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TS);
+ }
+ if ((isr & RTC_ISR_TSOVF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF);
+ }
+ }
+
+ /* This part is different depending on if the RTC has a TAMPCR or TAFCR
+ register.*/
+#if defined(RTC_TAFCR_TAMP1E)
+ tcr = RTCD1.rtc->TAFCR;
+ if ((tcr & RTC_TAFCR_TAMPIE) != 0U) {
+#if defined(RTC_ISR_TAMP1F)
+ if ((isr & RTC_ISR_TAMP1F) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1);
+ }
+#endif
+#if defined(RTC_ISR_TAMP2F)
+ if ((isr & RTC_ISR_TAMP2F) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2);
+ }
+#endif
+ }
+
+#else /* !defined(RTC_TAFCR_TAMP1E) */
+ tcr = RTCD1.rtc->TAMPCR;
+#if defined(RTC_ISR_TAMP1F)
+ if (((tcr & RTC_TAMPCR_TAMP1IE) != 0U) &&
+ ((isr & RTC_ISR_TAMP1F) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1);
+ }
+#endif
+#if defined(RTC_ISR_TAMP2F)
+ if (((tcr & RTC_TAMPCR_TAMP2IE) != 0U) &&
+ ((isr & RTC_ISR_TAMP2F) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2);
+ }
+#endif
+#if defined(RTC_ISR_TAMP3F)
+ if (((tcr & RTC_TAMPCR_TAMP3IE) != 0U) &&
+ ((isr & RTC_ISR_TAMP3F) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3);
+ }
+#endif
+#endif /* !defined(RTC_TAFCR_TAMP1E) */
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+/**
+ * @brief RTC wakeup interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_WKUP_HANDLER) {
+ uint32_t isr;
+
+ OSAL_IRQ_PROLOGUE();
+
+ isr = RTCD1.rtc->ISR;
+ RTCD1.rtc->ISR = isr & ~RTC_ISR_WUTF;
+
+ extiClearGroup1(EXTI_MASK1(STM32_RTC_WKUP_EXTI));
+
+ if (RTCD1.callback != NULL) {
+ uint32_t cr = RTCD1.rtc->CR;
+
+ if (((cr & RTC_CR_WUTIE) != 0U) && ((isr & RTC_ISR_WUTF) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP);
+ }
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief RTC alarm interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_ALARM_HANDLER) {
+ uint32_t isr, clear;
+
+ OSAL_IRQ_PROLOGUE();
+
+ clear = (0U
+#if defined(RTC_ISR_ALRAF)
+ | RTC_ISR_ALRAF
+#endif
+#if defined(RTC_ISR_ALRBF)
+ | RTC_ISR_ALRBF
+#endif
+ );
+
+ isr = RTCD1.rtc->ISR;
+ RTCD1.rtc->ISR = isr & ~clear;
+
+ extiClearGroup1(EXTI_MASK1(STM32_RTC_ALARM_EXTI));
+
+ if (RTCD1.callback != NULL) {
+ uint32_t cr = RTCD1.rtc->CR;
+#if defined(RTC_ISR_ALRAF)
+ if (((cr & RTC_CR_ALRAIE) != 0U) && ((isr & RTC_ISR_ALRAF) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A);
+ }
+#endif
+#if defined(RTC_ISR_ALRBF)
+ if (((cr & RTC_CR_ALRBIE) != 0U) && ((isr & RTC_ISR_ALRBF) != 0U)) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B);
+ }
+#endif
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "missing required RTC handlers definitions in registry"
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Enable access to registers.
+ *
+ * @notapi
+ */
+void rtc_lld_init(void) {
+
+ /* RTC object initialization.*/
+ rtcObjectInit(&RTCD1);
+
+ /* RTC pointer initialization.*/
+ RTCD1.rtc = RTC;
+
+ /* Disable write protection. */
+ RTCD1.rtc->WPR = 0xCA;
+ RTCD1.rtc->WPR = 0x53;
+
+ /* If calendar has not been initialized yet then proceed with the
+ initial setup.*/
+ if (!(RTCD1.rtc->ISR & RTC_ISR_INITS)) {
+
+ rtc_enter_init();
+
+ RTCD1.rtc->CR = STM32_RTC_CR_INIT;
+#if defined(RTC_TAFCR_TAMP1E)
+ RTCD1.rtc->TAFCR = STM32_RTC_TAMPCR_INIT;
+#else
+ RTCD1.rtc->TAMPCR = STM32_RTC_TAMPCR_INIT;
+#endif
+ RTCD1.rtc->ISR = RTC_ISR_INIT; /* Clearing all but RTC_ISR_INIT. */
+ RTCD1.rtc->PRER = STM32_RTC_PRER_BITS;
+ RTCD1.rtc->PRER = STM32_RTC_PRER_BITS;
+
+ rtc_exit_init();
+ }
+ else {
+ RTCD1.rtc->ISR &= ~RTC_ISR_RSF;
+ }
+
+ /* Callback initially disabled.*/
+ RTCD1.callback = NULL;
+
+ /* Enabling RTC-related EXTI lines.*/
+ extiEnableGroup1(EXTI_MASK1(STM32_RTC_ALARM_EXTI) |
+ EXTI_MASK1(STM32_RTC_TAMP_STAMP_EXTI) |
+ EXTI_MASK1(STM32_RTC_WKUP_EXTI),
+ EXTI_MODE_RISING_EDGE | EXTI_MODE_ACTION_INTERRUPT);
+
+ /* IRQ vectors permanently assigned to this driver.*/
+ STM32_RTC_IRQ_ENABLE();
+}
+
+/**
+ * @brief Set current time.
+ * @note Fractional part will be silently ignored. There is no possibility
+ * to set it on STM32 platform.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) {
+ uint32_t dr, tr;
+ syssts_t sts;
+
+ tr = rtc_encode_time(timespec);
+ dr = rtc_encode_date(timespec);
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ /* Writing the registers.*/
+ rtc_enter_init();
+ rtcp->rtc->TR = tr;
+ rtcp->rtc->DR = dr;
+ rtcp->rtc->CR = (rtcp->rtc->CR & ~(1U << RTC_CR_BKP_OFFSET)) |
+ (timespec->dstflag << RTC_CR_BKP_OFFSET);
+ rtc_exit_init();
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Get current time.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) {
+ uint32_t dr, tr, cr;
+ uint32_t subs;
+#if STM32_RTC_HAS_SUBSECONDS
+ uint32_t ssr;
+#endif /* STM32_RTC_HAS_SUBSECONDS */
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ /* Synchronization with the RTC and reading the registers, note
+ DR must be read last.*/
+ while ((rtcp->rtc->ISR & RTC_ISR_RSF) == 0)
+ ;
+#if STM32_RTC_HAS_SUBSECONDS
+ ssr = rtcp->rtc->SSR;
+#endif /* STM32_RTC_HAS_SUBSECONDS */
+ tr = rtcp->rtc->TR;
+ dr = rtcp->rtc->DR;
+ cr = rtcp->rtc->CR;
+ rtcp->rtc->ISR &= ~RTC_ISR_RSF;
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+
+ /* Decoding day time, this starts the atomic read sequence, see "Reading
+ the calendar" in the RTC documentation.*/
+ rtc_decode_time(tr, timespec);
+
+ /* If the RTC is capable of sub-second counting then the value is
+ normalized in milliseconds and added to the time.*/
+#if STM32_RTC_HAS_SUBSECONDS
+ subs = (((STM32_RTC_PRESS_VALUE - 1U) - ssr) * 1000U) / STM32_RTC_PRESS_VALUE;
+#else
+ subs = 0;
+#endif /* STM32_RTC_HAS_SUBSECONDS */
+ timespec->millisecond += subs;
+
+ /* Decoding date, this concludes the atomic read sequence.*/
+ rtc_decode_date(dr, timespec);
+
+ /* Retrieving the DST bit.*/
+ timespec->dstflag = (cr >> RTC_CR_BKP_OFFSET) & 1;
+}
+
+#if (RTC_ALARMS > 0) || defined(__DOXYGEN__)
+/**
+ * @brief Set alarm time.
+ * @note Default value after BKP domain reset for both comparators is 0.
+ * @note Function does not performs any checks of alarm time validity.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure.
+ * @param[in] alarm alarm identifier. Can be 0 or 1.
+ * @param[in] alarmspec pointer to a @p RTCAlarm structure.
+ *
+ * @notapi
+ */
+void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ if (alarm == 0) {
+ if (alarmspec != NULL) {
+ rtcp->rtc->CR &= ~RTC_CR_ALRAE;
+ while (!(rtcp->rtc->ISR & RTC_ISR_ALRAWF))
+ ;
+ rtcp->rtc->ALRMAR = alarmspec->alrmr;
+ rtcp->rtc->CR |= RTC_CR_ALRAE;
+ rtcp->rtc->CR |= RTC_CR_ALRAIE;
+ }
+ else {
+ rtcp->rtc->CR &= ~RTC_CR_ALRAIE;
+ rtcp->rtc->CR &= ~RTC_CR_ALRAE;
+ }
+ }
+#if RTC_ALARMS > 1
+ else {
+ if (alarmspec != NULL) {
+ rtcp->rtc->CR &= ~RTC_CR_ALRBE;
+ while (!(rtcp->rtc->ISR & RTC_ISR_ALRBWF))
+ ;
+ rtcp->rtc->ALRMBR = alarmspec->alrmr;
+ rtcp->rtc->CR |= RTC_CR_ALRBE;
+ rtcp->rtc->CR |= RTC_CR_ALRBIE;
+ }
+ else {
+ rtcp->rtc->CR &= ~RTC_CR_ALRBIE;
+ rtcp->rtc->CR &= ~RTC_CR_ALRBE;
+ }
+ }
+#endif /* RTC_ALARMS > 1 */
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Get alarm time.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier. Can be 0 or 1.
+ * @param[out] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec) {
+
+ if (alarm == 0)
+ alarmspec->alrmr = rtcp->rtc->ALRMAR;
+#if RTC_ALARMS > 1
+ else
+ alarmspec->alrmr = rtcp->rtc->ALRMBR;
+#endif /* RTC_ALARMS > 1 */
+}
+#endif /* RTC_ALARMS > 0 */
+
+/**
+ * @brief Enables or disables RTC callbacks.
+ * @details This function enables or disables callbacks, use a @p NULL pointer
+ * in order to disable a callback.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] callback callback function pointer or @p NULL
+ *
+ * @notapi
+ */
+void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
+
+ rtcp->callback = callback;
+}
+
+#if STM32_RTC_HAS_PERIODIC_WAKEUPS || defined(__DOXYGEN__)
+/**
+ * @brief Sets time of periodic wakeup.
+ * @note Default value after BKP domain reset is 0x0000FFFF
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] wakeupspec pointer to a @p RTCWakeup structure
+ *
+ * @api
+ */
+void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ if (wakeupspec != NULL) {
+ osalDbgCheck(wakeupspec->wutr != 0x30000);
+
+ rtcp->rtc->CR &= ~RTC_CR_WUTE;
+ rtcp->rtc->CR &= ~RTC_CR_WUTIE;
+ while (!(rtcp->rtc->ISR & RTC_ISR_WUTWF))
+ ;
+ rtcp->rtc->WUTR = wakeupspec->wutr & 0xFFFF;
+ rtcp->rtc->CR &= ~RTC_CR_WUCKSEL;
+ rtcp->rtc->CR |= (wakeupspec->wutr >> 16) & RTC_CR_WUCKSEL;
+ rtcp->rtc->CR |= RTC_CR_WUTIE;
+ rtcp->rtc->CR |= RTC_CR_WUTE;
+ }
+ else {
+ rtcp->rtc->CR &= ~RTC_CR_WUTE;
+ rtcp->rtc->CR &= ~RTC_CR_WUTIE;
+ }
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Gets time of periodic wakeup.
+ * @note Default value after BKP domain reset is 0x0000FFFF
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] wakeupspec pointer to a @p RTCWakeup structure
+ *
+ * @api
+ */
+void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ wakeupspec->wutr = 0;
+ wakeupspec->wutr |= rtcp->rtc->WUTR;
+ wakeupspec->wutr |= (((uint32_t)rtcp->rtc->CR) & 0x7) << 16;
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */
+
+#endif /* HAL_USE_RTC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h new file mode 100644 index 0000000..f60e798 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv2/hal_rtc_lld.h @@ -0,0 +1,249 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file RTCv2/hal_rtc_lld.h
+ * @brief STM32 RTC low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#ifndef HAL_RTC_LLD_H
+#define HAL_RTC_LLD_H
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Implementation capabilities
+ */
+/**
+ * @brief Callback support int the driver.
+ */
+#define RTC_SUPPORTS_CALLBACKS TRUE
+
+/**
+ * @brief Number of alarms available.
+ */
+#define RTC_ALARMS STM32_RTC_NUM_ALARMS
+
+/**
+ * @brief Presence of a local persistent storage.
+ */
+#define RTC_HAS_STORAGE (STM32_RTC_STORAGE_SIZE > 0)
+/** @} */
+
+/**
+ * @brief RTC PRER register initializer.
+ */
+#define RTC_PRER(a, s) ((((a) - 1) << 16) | ((s) - 1))
+
+/**
+ * @name Alarm helper macros
+ * @{
+ */
+#define RTC_ALRM_MSK4 (1U << 31)
+#define RTC_ALRM_WDSEL (1U << 30)
+#define RTC_ALRM_DT(n) ((n) << 28)
+#define RTC_ALRM_DU(n) ((n) << 24)
+#define RTC_ALRM_MSK3 (1U << 23)
+#define RTC_ALRM_HT(n) ((n) << 20)
+#define RTC_ALRM_HU(n) ((n) << 16)
+#define RTC_ALRM_MSK2 (1U << 15)
+#define RTC_ALRM_MNT(n) ((n) << 12)
+#define RTC_ALRM_MNU(n) ((n) << 8)
+#define RTC_ALRM_MSK1 (1U << 7)
+#define RTC_ALRM_ST(n) ((n) << 4)
+#define RTC_ALRM_SU(n) ((n) << 0)
+/** @} */
+
+/* Requires services from the EXTI driver.*/
+#if !defined(STM32_EXTI_REQUIRED)
+#define STM32_EXTI_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief RTC PRES register initialization.
+ * @note The default is calculated for a 32768Hz clock.
+ */
+#if !defined(STM32_RTC_PRESA_VALUE) || defined(__DOXYGEN__)
+#define STM32_RTC_PRESA_VALUE 32
+#endif
+
+/**
+ * @brief RTC PRESS divider initialization.
+ * @note The default is calculated for a 32768Hz clock.
+ */
+#if !defined(STM32_RTC_PRESS_VALUE) || defined(__DOXYGEN__)
+#define STM32_RTC_PRESS_VALUE 1024
+#endif
+
+/**
+ * @brief RTC CR register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ */
+#if !defined(STM32_RTC_CR_INIT) || defined(__DOXYGEN__)
+#define STM32_RTC_CR_INIT 0
+#endif
+
+/**
+ * @brief RTC TAMPCR register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ * @note On some devices this values goes in the similar TAFCR register.
+ */
+#if !defined(STM32_RTC_TAMPCR_INIT) || defined(__DOXYGEN__)
+#define STM32_RTC_TAMPCR_INIT 0
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if HAL_USE_RTC && !STM32_HAS_RTC
+#error "RTC not present in the selected device"
+#endif
+
+#if defined(STM32_RTC_CK) && !defined(STM32_RTCCLK)
+#define STM32_RTCCLK STM32_RTC_CK
+#endif
+
+#if !defined(STM32_RTCCLK)
+#error "RTC clock not exported by HAL layer"
+#endif
+
+#if STM32_PCLK1 < (STM32_RTCCLK * 7)
+#error "STM32_PCLK1 frequency is too low"
+#endif
+
+/**
+ * @brief Initialization for the RTC_PRER register.
+ */
+#define STM32_RTC_PRER_BITS RTC_PRER(STM32_RTC_PRESA_VALUE, \
+ STM32_RTC_PRESS_VALUE)
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of an RTC event.
+ */
+typedef enum {
+ RTC_EVENT_ALARM_A = 0, /** Alarm A. */
+ RTC_EVENT_ALARM_B = 1, /** Alarm B. */
+ RTC_EVENT_TS = 2, /** Time stamp. */
+ RTC_EVENT_TS_OVF = 3, /** Time stamp overflow. */
+ RTC_EVENT_TAMP1 = 4, /** Tamper 1. */
+ RTC_EVENT_TAMP2 = 5, /** Tamper 2- */
+ RTC_EVENT_TAMP3 = 6, /** Tamper 3. */
+ RTC_EVENT_WAKEUP = 7 /** Wakeup. */
+ } rtcevent_t;
+
+/**
+ * @brief Type of a generic RTC callback.
+ */
+typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
+
+/**
+ * @brief Type of a structure representing an RTC alarm time stamp.
+ */
+typedef struct hal_rtc_alarm {
+ /**
+ * @brief Type of an alarm as encoded in RTC ALRMxR registers.
+ */
+ uint32_t alrmr;
+} RTCAlarm;
+
+#if STM32_RTC_HAS_PERIODIC_WAKEUPS
+/**
+ * @brief Type of a wakeup as encoded in RTC WUTR register.
+ */
+typedef struct hal_rtc_wakeup {
+ /**
+ * @brief Wakeup as encoded in RTC WUTR register.
+ * @note ((WUTR == 0) || (WUCKSEL == 3)) are a forbidden combination.
+ * @note Bits 16..18 are copied in the CR bits 0..2 (WUCKSEL).
+ */
+ uint32_t wutr;
+} RTCWakeup;
+#endif
+
+/**
+ * @brief Implementation-specific @p RTCDriver fields.
+ */
+#define rtc_lld_driver_fields \
+ /* Pointer to the RTC registers block.*/ \
+ RTC_TypeDef *rtc; \
+ /* Callback pointer.*/ \
+ rtccb_t callback
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void rtc_lld_init(void);
+ void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec);
+ void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec);
+#if RTC_SUPPORTS_CALLBACKS == TRUE
+ void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
+#endif
+#if RTC_ALARMS > 0
+ void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec);
+ void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec);
+#endif
+#if STM32_RTC_HAS_PERIODIC_WAKEUPS
+ void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec);
+ void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec);
+#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_RTC */
+
+#endif /* HAL_RTC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk new file mode 100644 index 0000000..be3a5ad --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c new file mode 100644 index 0000000..6f776f3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c @@ -0,0 +1,717 @@ +/*
+ ChibiOS - Copyright (C) 2006..2019 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file RTCv3/hal_rtc_lld.c
+ * @brief STM32 RTC low level driver.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define RTC_TR_PM_OFFSET RTC_TR_PM_Pos
+#define RTC_TR_HT_OFFSET RTC_TR_HT_Pos
+#define RTC_TR_HU_OFFSET RTC_TR_HU_Pos
+#define RTC_TR_MNT_OFFSET RTC_TR_MNT_Pos
+#define RTC_TR_MNU_OFFSET RTC_TR_MNU_Pos
+#define RTC_TR_ST_OFFSET RTC_TR_ST_Pos
+#define RTC_TR_SU_OFFSET RTC_TR_SU_Pos
+
+#define RTC_DR_YT_OFFSET RTC_DR_YT_Pos
+#define RTC_DR_YU_OFFSET RTC_DR_YU_Pos
+#define RTC_DR_WDU_OFFSET RTC_DR_WDU_Pos
+#define RTC_DR_MT_OFFSET RTC_DR_MT_Pos
+#define RTC_DR_MU_OFFSET RTC_DR_MU_Pos
+#define RTC_DR_DT_OFFSET RTC_DR_DT_Pos
+#define RTC_DR_DU_OFFSET RTC_DR_DU_Pos
+
+#define RTC_CR_BKP_OFFSET RTC_CR_BKP_Pos
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC driver identifier.
+ */
+RTCDriver RTCD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Beginning of configuration procedure.
+ *
+ * @notapi
+ */
+static void rtc_enter_init(void) {
+
+ RTCD1.rtc->ICSR |= RTC_ICSR_INIT;
+ while ((RTCD1.rtc->ICSR & RTC_ICSR_INITF) == 0)
+ ;
+}
+
+/**
+ * @brief Finalizing of configuration procedure.
+ *
+ * @notapi
+ */
+static inline void rtc_exit_init(void) {
+
+ RTCD1.rtc->ICSR &= ~RTC_ICSR_INIT;
+}
+
+/**
+ * @brief Converts time from TR register encoding to timespec.
+ *
+ * @param[in] tr TR register value
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+static void rtc_decode_time(uint32_t tr, RTCDateTime *timespec) {
+ uint32_t n;
+
+ n = ((tr >> RTC_TR_HT_OFFSET) & 3) * 36000000;
+ n += ((tr >> RTC_TR_HU_OFFSET) & 15) * 3600000;
+ n += ((tr >> RTC_TR_MNT_OFFSET) & 7) * 600000;
+ n += ((tr >> RTC_TR_MNU_OFFSET) & 15) * 60000;
+ n += ((tr >> RTC_TR_ST_OFFSET) & 7) * 10000;
+ n += ((tr >> RTC_TR_SU_OFFSET) & 15) * 1000;
+ timespec->millisecond = n;
+}
+
+/**
+ * @brief Converts date from DR register encoding to timespec.
+ *
+ * @param[in] dr DR register value
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+static void rtc_decode_date(uint32_t dr, RTCDateTime *timespec) {
+
+ timespec->year = (((dr >> RTC_DR_YT_OFFSET) & 15) * 10) +
+ ((dr >> RTC_DR_YU_OFFSET) & 15);
+ timespec->month = (((dr >> RTC_TR_MNT_OFFSET) & 1) * 10) +
+ ((dr >> RTC_TR_MNU_OFFSET) & 15);
+ timespec->day = (((dr >> RTC_DR_DT_OFFSET) & 3) * 10) +
+ ((dr >> RTC_DR_DU_OFFSET) & 15);
+ timespec->dayofweek = ((dr >> RTC_DR_WDU_OFFSET) & 7) + 1;
+}
+
+/**
+ * @brief Converts time from timespec to TR register encoding.
+ *
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ * @return the TR register encoding.
+ *
+ * @notapi
+ */
+static uint32_t rtc_encode_time(const RTCDateTime *timespec) {
+ uint32_t n, tr = 0;
+
+ /* Subseconds cannot be set.*/
+ n = timespec->millisecond / 1000;
+
+ /* Seconds conversion.*/
+ tr = tr | ((n % 10) << RTC_TR_SU_OFFSET);
+ n /= 10;
+ tr = tr | ((n % 6) << RTC_TR_ST_OFFSET);
+ n /= 6;
+
+ /* Minutes conversion.*/
+ tr = tr | ((n % 10) << RTC_TR_MNU_OFFSET);
+ n /= 10;
+ tr = tr | ((n % 6) << RTC_TR_MNT_OFFSET);
+ n /= 6;
+
+ /* Hours conversion.*/
+ tr = tr | ((n % 10) << RTC_TR_HU_OFFSET);
+ n /= 10;
+ tr = tr | (n << RTC_TR_HT_OFFSET);
+
+ return tr;
+}
+
+/**
+ * @brief Converts a date from timespec to DR register encoding.
+ *
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ * @return the DR register encoding.
+ *
+ * @notapi
+ */
+static uint32_t rtc_encode_date(const RTCDateTime *timespec) {
+ uint32_t n, dr = 0;
+
+ /* Year conversion. Note, only years last two digits are considered.*/
+ n = timespec->year;
+ dr = dr | ((n % 10) << RTC_DR_YU_OFFSET);
+ n /= 10;
+ dr = dr | ((n % 10) << RTC_DR_YT_OFFSET);
+
+ /* Months conversion.*/
+ n = timespec->month;
+ dr = dr | ((n % 10) << RTC_DR_MU_OFFSET);
+ n /= 10;
+ dr = dr | ((n % 10) << RTC_DR_MT_OFFSET);
+
+ /* Days conversion.*/
+ n = timespec->day;
+ dr = dr | ((n % 10) << RTC_DR_DU_OFFSET);
+ n /= 10;
+ dr = dr | ((n % 10) << RTC_DR_DT_OFFSET);
+
+ /* Days of week conversion.*/
+ dr = dr | ((timespec->dayofweek) << RTC_DR_WDU_OFFSET);
+
+ return dr;
+}
+
+#if RTC_HAS_STORAGE == TRUE
+static size_t _getsize(void *instance) {
+
+ (void)instance;
+
+ return (size_t)STM32_RTC_STORAGE_SIZE;
+}
+
+static ps_error_t _read(void *instance, ps_offset_t offset,
+ size_t n, uint8_t *rp) {
+ volatile uint32_t *bkpr = &((RTCDriver *)instance)->tamp->BKP0R;
+ unsigned i;
+
+ chDbgCheck((instance != NULL) && (rp != NULL));
+ chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE));
+ chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) &&
+ (offset + n <= STM32_RTC_STORAGE_SIZE));
+
+ for (i = 0; i < (unsigned)n; i++) {
+ unsigned index = ((unsigned)offset + i) / sizeof (uint32_t);
+ unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t);
+ *rp++ = (uint8_t)(bkpr[index] >> (shift * 8U));
+ }
+
+ return PS_NO_ERROR;
+}
+
+static ps_error_t _write(void *instance, ps_offset_t offset,
+ size_t n, const uint8_t *wp) {
+ volatile uint32_t *bkpr = &((RTCDriver *)instance)->tamp->BKP0R;
+ unsigned i;
+
+ chDbgCheck((instance != NULL) && (wp != NULL));
+ chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE));
+ chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) &&
+ (offset + n <= STM32_RTC_STORAGE_SIZE));
+
+ for (i = 0; i < (unsigned)n; i++) {
+ unsigned index = ((unsigned)offset + i) / sizeof (uint32_t);
+ unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t);
+ uint32_t regval = bkpr[index];
+ regval &= ~(0xFFU << (shift * 8U));
+ regval |= (uint32_t)*wp++ << (shift * 8U);
+ bkpr[index] = regval;
+ }
+
+ return PS_NO_ERROR;
+}
+
+/**
+ * @brief VMT for the RTC storage file interface.
+ */
+struct RTCDriverVMT _rtc_lld_vmt = {
+ (size_t)0,
+ _getsize, _read, _write
+};
+#endif /* RTC_HAS_STORAGE == TRUE */
+
+/**
+ * @brief RTC ISR service routine.
+ *
+ */
+static void rtc_lld_serve_interrupt(void) {
+
+ uint32_t isr;
+
+ /* Get and clear the RTC interrupts. */
+ isr = RTCD1.rtc->MISR;
+ RTCD1.rtc->SCR = isr;
+
+ /* Clear EXTI events. */
+ STM32_RTC_CLEAR_ALL_EXTI();
+
+ /* Process call backs if enabled. */
+ if (RTCD1.callback != NULL) {
+
+#if defined(RTC_MISR_WUTMF)
+ if ((isr & RTC_MISR_WUTMF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP);
+ }
+#endif
+
+#if defined(RTC_MISR_ALRAMF)
+ if ((isr & RTC_MISR_ALRAMF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A);
+ }
+#endif
+#if defined(RTC_MISR_ALRBMF)
+ if ((isr & RTC_MISR_ALRBMF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B);
+ }
+#endif
+#if defined(RTC_MISR_ITSMF)
+ if ((isr & RTC_MISR_ITSMF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TS);
+ }
+#endif
+#if defined(RTC_MISR_TSOVMF)
+ if ((isr & RTC_MISR_TSOVMF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF);
+ }
+#endif
+
+ /* Get and clear the TAMP interrupts. */
+ isr = RTCD1.tamp->MISR;
+ RTCD1.tamp->SCR = isr;
+#if defined(TAMP_MISR_TAMP1MF)
+ if ((isr & TAMP_MISR_TAMP1MF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1);
+ }
+#endif
+#if defined(TAMP_MISR_TAMP2MF)
+ if ((isr & TAMP_MISR_TAMP2MF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2);
+ }
+#endif
+#if defined(TAMP_MISR_ITAMP3MF)
+ if ((isr & TAMP_MISR_ITAMP3MF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3);
+ }
+#endif
+#if defined(TAMP_MISR_ITAMP4MF)
+ if ((isr & TAMP_MISR_ITAMP4MF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP4);
+ }
+#endif
+#if defined(TAMP_MISR_ITAMP5MF)
+ if ((isr & TAMP_MISR_ITAMP5MF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP5);
+ }
+#endif
+#if defined(TAMP_MISR_ITAMP6MF)
+ if ((isr & TAMP_MISR_ITAMP6MF) != 0U) {
+ RTCD1.callback(&RTCD1, RTC_EVENT_TAMP6);
+ }
+#endif
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if defined(STM32_RTC_COMMON_HANDLER)
+#if !defined(STM32_RTC_SUPPRESS_COMMON_ISR)
+/**
+ * @brief RTC common interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_COMMON_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ rtc_lld_serve_interrupt();
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_RTC_SUPPRESS_COMMON_ISR) */
+
+#elif defined(STM32_RTC_TAMP_STAMP_HANDLER) && \
+ defined(STM32_RTC_WKUP_HANDLER) && \
+ defined(STM32_RTC_ALARM_HANDLER)
+/**
+ * @brief RTC TAMP/STAMP interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_TAMP_STAMP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ rtc_lld_serve_interrupt();
+
+ OSAL_IRQ_EPILOGUE();
+}
+/**
+ * @brief RTC wakeup interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_WKUP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ rtc_lld_serve_interrupt();
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief RTC alarm interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_RTC_ALARM_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ rtc_lld_serve_interrupt();
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#else
+#error "missing required RTC handler definitions in registry"
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Enable access to registers.
+ *
+ * @notapi
+ */
+void rtc_lld_init(void) {
+
+ /* RTC object initialization.*/
+ rtcObjectInit(&RTCD1);
+
+ /* RTC pointer initialization.*/
+ RTCD1.rtc = RTC;
+
+ /* Disable write protection. */
+ RTCD1.rtc->WPR = 0xCA;
+ RTCD1.rtc->WPR = 0x53;
+
+ /* If calendar has not been initialized yet then proceed with the
+ initial setup.*/
+ if (!(RTCD1.rtc->ICSR & RTC_ICSR_INITS)) {
+
+ rtc_enter_init();
+
+ RTCD1.rtc->CR |= (STM32_RTC_CR_INIT & STM32_RTC_CR_MASK);
+ /* Setting PRER has to be done as two writes. Write Sync part first
+ then Sync + Async. */
+ RTCD1.rtc->PRER = STM32_RTC_PRER_BITS & 0x7FFF;
+ RTCD1.rtc->PRER = STM32_RTC_PRER_BITS;
+
+ rtc_exit_init();
+ }
+ else {
+ RTCD1.rtc->ICSR &= ~RTC_ICSR_RSF;
+ }
+
+ /* TAMP pointer initialization. */
+ RTCD1.tamp = TAMP;
+
+ /* Initialise TAMP registers. */
+ RTCD1.tamp->CR1 |= (STM32_TAMP_CR1_INIT & STM32_TAMP_CR1_MASK);
+ RTCD1.tamp->CR2 |= (STM32_TAMP_CR2_INIT & STM32_TAMP_CR2_MASK);
+ RTCD1.tamp->FLTCR |= (STM32_TAMP_FLTCR_INIT & STM32_TAMP_FLTCR_MASK);
+ RTCD1.tamp->IER |= (STM32_TAMP_IER_INIT & STM32_TAMP_IER_MASK);
+
+ /* Callback initially disabled.*/
+ RTCD1.callback = NULL;
+
+ /* Enabling RTC-related EXTI lines.*/
+ STM32_RTC_ENABLE_ALL_EXTI();
+
+ /* IRQ vectors permanently assigned to this driver.*/
+ STM32_RTC_IRQ_ENABLE();
+}
+
+/**
+ * @brief Set current time.
+ * @note Fractional part will be silently ignored. There is no possibility
+ * to set it on STM32 platform.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) {
+ uint32_t dr, tr;
+ syssts_t sts;
+
+ tr = rtc_encode_time(timespec);
+ dr = rtc_encode_date(timespec);
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ /* Writing the registers.*/
+ rtc_enter_init();
+ rtcp->rtc->TR = tr;
+ rtcp->rtc->DR = dr;
+ rtcp->rtc->CR = (rtcp->rtc->CR & ~(1U << RTC_CR_BKP_OFFSET)) |
+ (timespec->dstflag << RTC_CR_BKP_OFFSET);
+ rtc_exit_init();
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Get current time.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] timespec pointer to a @p RTCDateTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) {
+ uint32_t dr, tr, cr;
+ uint32_t subs;
+#if STM32_RTC_HAS_SUBSECONDS
+ uint32_t ssr;
+#endif /* STM32_RTC_HAS_SUBSECONDS */
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ /* Synchronization with the RTC and reading the registers, note
+ DR must be read last.*/
+ while ((rtcp->rtc->ICSR & RTC_ICSR_RSF) == 0)
+ ;
+#if STM32_RTC_HAS_SUBSECONDS
+ ssr = rtcp->rtc->SSR;
+#endif /* STM32_RTC_HAS_SUBSECONDS */
+ tr = rtcp->rtc->TR;
+ dr = rtcp->rtc->DR;
+ cr = rtcp->rtc->CR;
+ rtcp->rtc->ICSR &= ~RTC_ICSR_RSF;
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+
+ /* Decoding day time, this starts the atomic read sequence, see "Reading
+ the calendar" in the RTC documentation.*/
+ rtc_decode_time(tr, timespec);
+
+ /* If the RTC is capable of sub-second counting then the value is
+ normalized in milliseconds and added to the time.*/
+#if STM32_RTC_HAS_SUBSECONDS
+ subs = (((STM32_RTC_PRESS_VALUE - 1U) - ssr) * 1000U) / STM32_RTC_PRESS_VALUE;
+#else
+ subs = 0;
+#endif /* STM32_RTC_HAS_SUBSECONDS */
+ timespec->millisecond += subs;
+
+ /* Decoding date, this concludes the atomic read sequence.*/
+ rtc_decode_date(dr, timespec);
+
+ /* Retrieving the DST bit.*/
+ timespec->dstflag = (cr >> RTC_CR_BKP_OFFSET) & 1;
+}
+
+#if (RTC_ALARMS > 0) || defined(__DOXYGEN__)
+/**
+ * @brief Set alarm time.
+ * @note Default value after BKP domain reset for both comparators is 0.
+ * @note Function does not performs any checks of alarm time validity.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure.
+ * @param[in] alarm alarm identifier. Can be 0 or 1.
+ * @param[in] alarmspec pointer to a @p RTCAlarm structure.
+ *
+ * @notapi
+ */
+void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ if (alarm == 0) {
+ if (alarmspec != NULL) {
+ rtcp->rtc->CR &= ~RTC_CR_ALRAE;
+ while (!(rtcp->rtc->ICSR & RTC_ICSR_ALRAWF))
+ ;
+ rtcp->rtc->ALRMAR = alarmspec->alrmr;
+ rtcp->rtc->CR |= RTC_CR_ALRAE;
+ rtcp->rtc->CR |= RTC_CR_ALRAIE;
+ }
+ else {
+ rtcp->rtc->CR &= ~RTC_CR_ALRAIE;
+ rtcp->rtc->CR &= ~RTC_CR_ALRAE;
+ }
+ }
+#if RTC_ALARMS > 1
+ else {
+ if (alarmspec != NULL) {
+ rtcp->rtc->CR &= ~RTC_CR_ALRBE;
+ while (!(rtcp->rtc->ICSR & RTC_ICSR_ALRBWF))
+ ;
+ rtcp->rtc->ALRMBR = alarmspec->alrmr;
+ rtcp->rtc->CR |= RTC_CR_ALRBE;
+ rtcp->rtc->CR |= RTC_CR_ALRBIE;
+ }
+ else {
+ rtcp->rtc->CR &= ~RTC_CR_ALRBIE;
+ rtcp->rtc->CR &= ~RTC_CR_ALRBE;
+ }
+ }
+#endif /* RTC_ALARMS > 1 */
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Get alarm time.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier. Can be 0 or 1.
+ * @param[out] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec) {
+
+ if (alarm == 0)
+ alarmspec->alrmr = rtcp->rtc->ALRMAR;
+#if RTC_ALARMS > 1
+ else
+ alarmspec->alrmr = rtcp->rtc->ALRMBR;
+#endif /* RTC_ALARMS > 1 */
+}
+#endif /* RTC_ALARMS > 0 */
+
+/**
+ * @brief Enables or disables RTC callbacks.
+ * @details This function enables or disables callbacks, use a @p NULL pointer
+ * in order to disable a callback.
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] callback callback function pointer or @p NULL
+ *
+ * @notapi
+ */
+void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
+
+ rtcp->callback = callback;
+}
+
+#if STM32_RTC_HAS_PERIODIC_WAKEUPS || defined(__DOXYGEN__)
+/**
+ * @brief Sets time of periodic wakeup.
+ * @note Default value after BKP domain reset is 0x0000FFFF
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] wakeupspec pointer to a @p RTCWakeup structure
+ *
+ * @api
+ */
+void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ if (wakeupspec != NULL) {
+ osalDbgCheck(wakeupspec->wutr != 0x30000);
+
+ rtcp->rtc->CR &= ~RTC_CR_WUTE;
+ rtcp->rtc->CR &= ~RTC_CR_WUTIE;
+ while (!(rtcp->rtc->ICSR & RTC_ICSR_WUTWF))
+ ;
+ rtcp->rtc->WUTR = wakeupspec->wutr & 0xFFFF;
+ rtcp->rtc->CR &= ~RTC_CR_WUCKSEL;
+ rtcp->rtc->CR |= (wakeupspec->wutr >> 16) & RTC_CR_WUCKSEL;
+ rtcp->rtc->CR |= RTC_CR_WUTIE;
+ rtcp->rtc->CR |= RTC_CR_WUTE;
+ }
+ else {
+ rtcp->rtc->CR &= ~RTC_CR_WUTE;
+ rtcp->rtc->CR &= ~RTC_CR_WUTIE;
+ }
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+
+/**
+ * @brief Gets time of periodic wakeup.
+ * @note Default value after BKP domain reset is 0x0000FFFF
+ * @note The function can be called from any context.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] wakeupspec pointer to a @p RTCWakeup structure
+ *
+ * @api
+ */
+void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec) {
+ syssts_t sts;
+
+ /* Entering a reentrant critical zone.*/
+ sts = osalSysGetStatusAndLockX();
+
+ wakeupspec->wutr = 0;
+ wakeupspec->wutr |= rtcp->rtc->WUTR;
+ wakeupspec->wutr |= (((uint32_t)rtcp->rtc->CR) & 0x7) << 16;
+
+ /* Leaving a reentrant critical zone.*/
+ osalSysRestoreStatusX(sts);
+}
+#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */
+
+#endif /* HAL_USE_RTC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h new file mode 100644 index 0000000..4097a62 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h @@ -0,0 +1,289 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file RTCv3/hal_rtc_lld.h
+ * @brief STM32 RTC low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#ifndef HAL_RTC_LLD_H
+#define HAL_RTC_LLD_H
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Implementation capabilities
+ */
+/**
+ * @brief Callback support int the driver.
+ */
+#define RTC_SUPPORTS_CALLBACKS TRUE
+
+/**
+ * @brief Number of alarms available.
+ */
+#define RTC_ALARMS STM32_RTC_NUM_ALARMS
+
+/**
+ * @brief Presence of a local persistent storage.
+ */
+#define RTC_HAS_STORAGE (STM32_RTC_STORAGE_SIZE > 0)
+/** @} */
+
+/**
+ * @brief RTC PRER register initializer.
+ */
+#define RTC_PRER(a, s) ((((a) - 1) << 16) | ((s) - 1))
+
+/**
+ * @name Alarm helper macros
+ * @{
+ */
+#define RTC_ALRM_MSK4 (1U << 31)
+#define RTC_ALRM_WDSEL (1U << 30)
+#define RTC_ALRM_DT(n) ((n) << 28)
+#define RTC_ALRM_DU(n) ((n) << 24)
+#define RTC_ALRM_MSK3 (1U << 23)
+#define RTC_ALRM_HT(n) ((n) << 20)
+#define RTC_ALRM_HU(n) ((n) << 16)
+#define RTC_ALRM_MSK2 (1U << 15)
+#define RTC_ALRM_MNT(n) ((n) << 12)
+#define RTC_ALRM_MNU(n) ((n) << 8)
+#define RTC_ALRM_MSK1 (1U << 7)
+#define RTC_ALRM_ST(n) ((n) << 4)
+#define RTC_ALRM_SU(n) ((n) << 0)
+/** @} */
+
+/* Requires services from the EXTI driver.*/
+#if !defined(STM32_EXTI_REQUIRED)
+#define STM32_EXTI_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief RTC PRESA register initialization.
+ * @note The default is calculated for a 32768Hz clock.
+ */
+#if !defined(STM32_RTC_PRESA_VALUE) || defined(__DOXYGEN__)
+#define STM32_RTC_PRESA_VALUE 32
+#endif
+
+/**
+ * @brief RTC PRESS divider initialization.
+ * @note The default is calculated for a 32768Hz clock.
+ */
+#if !defined(STM32_RTC_PRESS_VALUE) || defined(__DOXYGEN__)
+#define STM32_RTC_PRESS_VALUE 1024
+#endif
+
+/**
+ * @brief RTC CR register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ */
+#if !defined(STM32_RTC_CR_INIT) || defined(__DOXYGEN__)
+#define STM32_RTC_CR_INIT 0
+#endif
+
+/**
+ * @brief TAMP register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ * @note On some devices this values goes in the similar TAFCR register.
+ */
+#if !defined(STM32_TAMP_CR1_INIT) || defined(__DOXYGEN__)
+#define STM32_TAMP_CR1_INIT 0
+#endif
+
+/**
+ * @brief TAMP register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ * @note On some devices this values goes in the similar TAFCR register.
+ */
+#if !defined(STM32_TAMP_CR2_INIT) || defined(__DOXYGEN__)
+#define STM32_TAMP_CR2_INIT 0
+#endif
+
+/**
+ * @brief TAMP register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ * @note On some devices this values goes in the similar TAFCR register.
+ */
+#if !defined(STM32_TAMP_FLTCR_INIT) || defined(__DOXYGEN__)
+#define STM32_TAMP_FLTCR_INIT 0
+#endif
+
+/**
+ * @brief TAMP register initialization value.
+ * @note Use this value to initialize features not directly handled by
+ * the RTC driver.
+ * @note On some devices this values goes in the similar TAFCR register.
+ */
+#if !defined(STM32_TAMP_IER_INIT) || defined(__DOXYGEN__)
+#define STM32_TAMP_IER_INIT 0
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if HAL_USE_RTC && !STM32_HAS_RTC
+#error "RTC not present in the selected device"
+#endif
+
+#if defined(STM32_RTC_CK) && !defined(STM32_RTCCLK)
+#define STM32_RTCCLK STM32_RTC_CK
+#endif
+
+#if !defined(STM32_RTCCLK)
+#error "RTC clock not exported by HAL layer"
+#endif
+
+#if STM32_RTCCLK == 0
+#error "RTC has no clock source selected"
+#endif
+
+#if STM32_PCLK1 < (STM32_RTCCLK * 7)
+#error "STM32_PCLK1 frequency is too low for RTC"
+#endif
+
+/**
+ * @brief Initialization for the RTC_PRER register.
+ */
+#define STM32_RTC_PRER_BITS RTC_PRER(STM32_RTC_PRESA_VALUE, \
+ STM32_RTC_PRESS_VALUE)
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of an RTC event.
+ */
+typedef enum {
+ RTC_EVENT_ALARM_A = 0, /** Alarm A. */
+ RTC_EVENT_ALARM_B = 1, /** Alarm B. */
+ RTC_EVENT_TS = 2, /** Time stamp. */
+ RTC_EVENT_TS_OVF = 3, /** Time stamp overflow. */
+ RTC_EVENT_TAMP1 = 4, /** Tamper 1. */
+ RTC_EVENT_TAMP2 = 5, /** Tamper 2- */
+ RTC_EVENT_TAMP3 = 6, /** Tamper 3. */
+ RTC_EVENT_TAMP4 = 7, /** Tamper 4. */
+ RTC_EVENT_TAMP5 = 8, /** Tamper 5. */
+ RTC_EVENT_TAMP6 = 9, /** Tamper 6. */
+ RTC_EVENT_WAKEUP = 10, /** Wakeup. */
+ } rtcevent_t;
+
+/**
+ * @brief Type of a generic RTC callback.
+ */
+typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
+
+/**
+ * @brief Type of a structure representing an RTC alarm time stamp.
+ */
+typedef struct hal_rtc_alarm {
+ /**
+ * @brief Type of an alarm as encoded in RTC ALRMxR registers.
+ */
+ uint32_t alrmr;
+} RTCAlarm;
+
+#if STM32_RTC_HAS_PERIODIC_WAKEUPS
+/**
+ * @brief Type of a wakeup as encoded in RTC WUTR register.
+ */
+typedef struct hal_rtc_wakeup {
+ /**
+ * @brief Wakeup as encoded in RTC WUTR register.
+ * @note ((WUTR == 0) || (WUCKSEL == 3)) are a forbidden combination.
+ * @note Bits 16..18 are copied in the CR bits 0..2 (WUCKSEL).
+ */
+ uint32_t wutr;
+} RTCWakeup;
+#endif
+
+/**
+ * @brief Implementation-specific @p RTCDriver fields.
+ */
+#define rtc_lld_driver_fields \
+ /* Pointer to the RTC registers block.*/ \
+ RTC_TypeDef *rtc; \
+ /* RTC event callback pointer.*/ \
+ rtccb_t callback; \
+ /* Pointer to TAMPER registers block. */ \
+ TAMP_TypeDef *tamp
+
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void rtc_lld_init(void);
+ void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec);
+ void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec);
+#if RTC_SUPPORTS_CALLBACKS == TRUE
+ void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
+#endif
+#if RTC_ALARMS > 0
+ void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec);
+ void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec);
+#endif
+#if STM32_RTC_HAS_PERIODIC_WAKEUPS
+ void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec);
+ void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec);
+#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_RTC */
+
+#endif /* HAL_RTC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk new file mode 100644 index 0000000..a1ce6d4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c new file mode 100644 index 0000000..37d4989 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.c @@ -0,0 +1,876 @@ +/*
+ 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 SDIOv1/hal_sdc_lld.c
+ * @brief STM32 SDC subsystem low level driver source.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SDC_SDIO_DMA_STREAM, \
+ STM32_SDC_SDIO_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SDCD1 driver identifier.*/
+SDCDriver SDCD1;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+#if STM32_SDC_SDIO_UNALIGNED_SUPPORT
+/**
+ * @brief Buffer for temporary storage during unaligned transfers.
+ */
+static union {
+ uint32_t alignment;
+ uint8_t buf[MMCSD_BLOCK_SIZE];
+} u;
+#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+
+/**
+ * @brief SDIO default configuration.
+ */
+static const SDCConfig sdc_default_cfg = {
+ SDC_MODE_4BIT
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Prepares to handle read transaction.
+ * @details Designed for read special registers from card.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[out] buf pointer to the read buffer
+ * @param[in] bytes number of bytes to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp,
+ uint8_t *buf, uint32_t bytes) {
+ osalDbgCheck(bytes < 0x1000000);
+
+ sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT;
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaStreamSetMemory0(sdcp->dma, buf);
+ dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t));
+ dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M);
+ dmaStreamEnable(sdcp->dma);
+
+ /* Setting up data transfer.*/
+ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
+ sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE |
+ SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_STBITERRIE |
+ SDIO_MASK_RXOVERRIE |
+ SDIO_MASK_DATAENDIE;
+ sdcp->sdio->DLEN = bytes;
+
+ /* Transaction starts just after DTEN bit setting.*/
+ sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DTMODE | /* Multibyte data transfer.*/
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Prepares card to handle read transaction.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[in] n number of blocks to read
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk,
+ uint32_t n, uint32_t *resp) {
+
+ /* Driver handles data in 512 bytes blocks (just like HC cards). But if we
+ have not HC card than we must convert address from blocks to bytes.*/
+ if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY))
+ startblk *= MMCSD_BLOCK_SIZE;
+
+ if (n > 1) {
+ /* Send read multiple blocks command to card.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+ else {
+ /* Send read single block command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Prepares card to handle write transaction.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[in] n number of blocks to write
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk,
+ uint32_t n, uint32_t *resp) {
+
+ /* Driver handles data in 512 bytes blocks (just like HC cards). But if we
+ have not HC card than we must convert address from blocks to bytes.*/
+ if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY))
+ startblk *= MMCSD_BLOCK_SIZE;
+
+ if (n > 1) {
+ /* Write multiple blocks command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+ else {
+ /* Write single block command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Wait end of data transaction and performs finalizations.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] n number of blocks in transaction
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ */
+static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n,
+ uint32_t *resp) {
+
+ /* Note the mask is checked before going to sleep because the interrupt
+ may have occurred before reaching the critical zone.*/
+ osalSysLock();
+ if (sdcp->sdio->MASK != 0)
+ osalThreadSuspendS(&sdcp->thread);
+ if ((sdcp->sdio->STA & SDIO_STA_DATAEND) == 0) {
+ osalSysUnlock();
+ return HAL_FAILED;
+ }
+
+#if (defined(STM32F4XX) || defined(STM32F2XX))
+ /* Wait until DMA channel enabled to be sure that all data transferred.*/
+ while (sdcp->dma->stream->CR & STM32_DMA_CR_EN)
+ ;
+
+ /* DMA event flags must be manually cleared.*/
+ dmaStreamClearInterrupt(sdcp->dma);
+
+ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
+ sdcp->sdio->DCTRL = 0;
+ osalSysUnlock();
+#else
+ /* Waits for transfer completion at DMA level, then the stream is
+ disabled and cleared.*/
+ dmaWaitCompletion(sdcp->dma);
+
+ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
+ sdcp->sdio->DCTRL = 0;
+ osalSysUnlock();
+#endif
+
+ /* Finalize transaction.*/
+ if (n > 1)
+ return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Gets SDC errors.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] sta value of the STA register
+ *
+ * @notapi
+ */
+static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) {
+ uint32_t errors = SDC_NO_ERROR;
+
+ if (sta & SDIO_STA_CCRCFAIL)
+ errors |= SDC_CMD_CRC_ERROR;
+ if (sta & SDIO_STA_DCRCFAIL)
+ errors |= SDC_DATA_CRC_ERROR;
+ if (sta & SDIO_STA_CTIMEOUT)
+ errors |= SDC_COMMAND_TIMEOUT;
+ if (sta & SDIO_STA_DTIMEOUT)
+ errors |= SDC_DATA_TIMEOUT;
+ if (sta & SDIO_STA_TXUNDERR)
+ errors |= SDC_TX_UNDERRUN;
+ if (sta & SDIO_STA_RXOVERR)
+ errors |= SDC_RX_OVERRUN;
+ if (sta & SDIO_STA_STBITERR)
+ errors |= SDC_STARTBIT_ERROR;
+
+ sdcp->errors |= errors;
+}
+
+/**
+ * @brief Performs clean transaction stopping in case of errors.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] n number of blocks in transaction
+ * @param[in] resp pointer to the response buffer
+ *
+ * @notapi
+ */
+static void sdc_lld_error_cleanup(SDCDriver *sdcp,
+ uint32_t n,
+ uint32_t *resp) {
+ uint32_t sta = sdcp->sdio->STA;
+
+ dmaStreamClearInterrupt(sdcp->dma);
+ dmaStreamDisable(sdcp->dma);
+ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
+ sdcp->sdio->MASK = 0;
+ sdcp->sdio->DCTRL = 0;
+ sdc_lld_collect_errors(sdcp, sta);
+ if (n > 1)
+ sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if !defined(STM32_SDIO_HANDLER)
+#error "STM32_SDIO_HANDLER not defined"
+#endif
+/**
+ * @brief SDIO IRQ handler.
+ * @details It just wakes transaction thread. All error handling performs in
+ * that thread.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SDIO_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ osalSysLockFromISR();
+
+ /* Disables the source but the status flags are not reset because the
+ read/write functions needs to check them.*/
+ SDIO->MASK = 0;
+
+ osalThreadResumeI(&SDCD1.thread, MSG_OK);
+
+ osalSysUnlockFromISR();
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SDC driver initialization.
+ *
+ * @notapi
+ */
+void sdc_lld_init(void) {
+
+ sdcObjectInit(&SDCD1);
+ SDCD1.thread = NULL;
+ SDCD1.dma = NULL;
+ SDCD1.sdio = SDIO;
+ nvicEnableVector(STM32_SDIO_NUMBER, STM32_SDC_SDIO_IRQ_PRIORITY);
+}
+
+/**
+ * @brief Configures and activates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start(SDCDriver *sdcp) {
+
+ /* Checking configuration, using a default if NULL has been passed.*/
+ if (sdcp->config == NULL) {
+ sdcp->config = &sdc_default_cfg;
+ }
+
+ sdcp->dmamode = STM32_DMA_CR_CHSEL(DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_WORD |
+ STM32_DMA_CR_MSIZE_WORD |
+ STM32_DMA_CR_MINC;
+
+#if (defined(STM32F4XX) || defined(STM32F2XX))
+ sdcp->dmamode |= STM32_DMA_CR_PFCTRL |
+ STM32_DMA_CR_PBURST_INCR4 |
+ STM32_DMA_CR_MBURST_INCR4;
+#endif
+
+ if (sdcp->state == BLK_STOP) {
+ sdcp->dma = dmaStreamAllocI(STM32_SDC_SDIO_DMA_STREAM,
+ STM32_SDC_SDIO_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(sdcp->dma != NULL, "unable to allocate stream");
+
+ dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdio->FIFO);
+#if (defined(STM32F4XX) || defined(STM32F2XX))
+ dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_FULL);
+#endif
+ rccEnableSDIO(true);
+ }
+
+ /* Configuration, card clock is initially stopped.*/
+ sdcp->sdio->POWER = 0;
+ sdcp->sdio->CLKCR = 0;
+ sdcp->sdio->DCTRL = 0;
+ sdcp->sdio->DTIMER = 0;
+}
+
+/**
+ * @brief Deactivates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop(SDCDriver *sdcp) {
+
+ if (sdcp->state != BLK_STOP) {
+
+ /* SDIO deactivation.*/
+ sdcp->sdio->POWER = 0;
+ sdcp->sdio->CLKCR = 0;
+ sdcp->sdio->DCTRL = 0;
+ sdcp->sdio->DTIMER = 0;
+
+ /* DMA stream released.*/
+ dmaStreamFreeI(sdcp->dma);
+ sdcp->dma = NULL;
+
+ /* Clock deactivation.*/
+ rccDisableSDIO();
+ }
+}
+
+/**
+ * @brief Starts the SDIO clock and sets it to init mode (400kHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start_clk(SDCDriver *sdcp) {
+
+ /* Initial clock setting: 400kHz, 1bit mode.*/
+ sdcp->sdio->CLKCR = STM32_SDIO_DIV_LS;
+ sdcp->sdio->POWER |= SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1;
+ sdcp->sdio->CLKCR |= SDIO_CLKCR_CLKEN;
+
+ /* Clock activation delay.*/
+ osalThreadSleep(OSAL_MS2I(STM32_SDC_CLOCK_ACTIVATION_DELAY));
+}
+
+/**
+ * @brief Sets the SDIO clock to data mode (25MHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] clk the clock mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) {
+
+#if STM32_SDC_SDIO_50MHZ
+ if (SDC_CLK_50MHz == clk) {
+ sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS
+ | SDIO_CLKCR_BYPASS;
+ }
+ else
+ sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS;
+#else
+ (void)clk;
+
+ sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS;
+#endif
+}
+
+/**
+ * @brief Stops the SDIO clock.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop_clk(SDCDriver *sdcp) {
+
+ sdcp->sdio->CLKCR = 0;
+ sdcp->sdio->POWER = 0;
+}
+
+/**
+ * @brief Switches the bus to 4 bits mode.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] mode bus mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) {
+ uint32_t clk = sdcp->sdio->CLKCR & ~SDIO_CLKCR_WIDBUS;
+
+ switch (mode) {
+ case SDC_MODE_1BIT:
+ sdcp->sdio->CLKCR = clk;
+ break;
+ case SDC_MODE_4BIT:
+ sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_0;
+ break;
+ case SDC_MODE_8BIT:
+ sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_1;
+ break;
+ }
+}
+
+/**
+ * @brief Sends an SDIO command with no response expected.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ *
+ * @notapi
+ */
+void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) {
+
+ sdcp->sdio->ARG = arg;
+ sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_CPSMEN;
+ while ((sdcp->sdio->STA & SDIO_STA_CMDSENT) == 0)
+ ;
+ sdcp->sdio->ICR = SDIO_ICR_CMDSENTC;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected.
+ * @note The CRC is not verified.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ sdcp->sdio->ARG = arg;
+ sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN;
+ while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL);
+ if ((sta & (SDIO_STA_CTIMEOUT)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ *resp = sdcp->sdio->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ sdcp->sdio->ARG = arg;
+ sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN;
+ while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL);
+ if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ *resp = sdcp->sdio->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Sends an SDIO command with a long response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (four words)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ (void)sdcp;
+
+ sdcp->sdio->ARG = arg;
+ sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_WAITRESP_1 |
+ SDIO_CMD_CPSMEN;
+ while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL);
+ if ((sta & (STM32_SDIO_STA_ERROR_MASK)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ /* Save bytes in reverse order because MSB in response comes first.*/
+ *resp++ = sdcp->sdio->RESP4;
+ *resp++ = sdcp->sdio->RESP3;
+ *resp++ = sdcp->sdio->RESP2;
+ *resp = sdcp->sdio->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Reads special registers using data bus.
+ * @details Needs only during card detection procedure.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[out] buf pointer to the read buffer
+ * @param[in] bytes number of bytes to read
+ * @param[in] cmd card command
+ * @param[in] arg argument for command
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes,
+ uint8_t cmd, uint32_t arg) {
+ uint32_t resp[1];
+
+ if (sdc_lld_prepare_read_bytes(sdcp, buf, bytes))
+ goto error;
+
+ if (sdc_lld_send_cmd_short_crc(sdcp, cmd, arg, resp)
+ || MMCSD_R1_ERROR(resp[0]))
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, 1, resp))
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, 1, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] blocks number of blocks to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks) {
+ uint32_t resp[1];
+
+ osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE);
+
+ sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT;
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaStreamSetMemory0(sdcp->dma, buf);
+ dmaStreamSetTransactionSize(sdcp->dma,
+ (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t));
+ dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M);
+ dmaStreamEnable(sdcp->dma);
+
+ /* Setting up data transfer.*/
+ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
+ sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE |
+ SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_STBITERRIE |
+ SDIO_MASK_RXOVERRIE |
+ SDIO_MASK_DATAENDIE;
+ sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE;
+
+ /* Transaction starts just after DTEN bit setting.*/
+ sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DBLOCKSIZE_3 |
+ SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true)
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, blocks, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] n number of blocks to write
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks) {
+ uint32_t resp[1];
+
+ osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE);
+
+ sdcp->sdio->DTIMER = STM32_SDC_WRITE_TIMEOUT;
+
+ /* Checks for errors and waits for the card to be ready for writing.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaStreamSetMemory0(sdcp->dma, buf);
+ dmaStreamSetTransactionSize(sdcp->dma,
+ (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t));
+ dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P);
+ dmaStreamEnable(sdcp->dma);
+
+ /* Setting up data transfer.*/
+ sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
+ sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE |
+ SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_STBITERRIE |
+ SDIO_MASK_TXUNDERRIE |
+ SDIO_MASK_DATAENDIE;
+ sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE;
+
+ /* Talk to card what we want from it.*/
+ if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == true)
+ goto error;
+
+ /* Transaction starts just after DTEN bit setting.*/
+ sdcp->sdio->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 |
+ SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, blocks, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] blocks number of blocks to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks) {
+
+#if STM32_SDC_SDIO_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < blocks; i++) {
+ if (sdc_lld_read_aligned(sdcp, startblk, u.buf, 1))
+ return HAL_FAILED;
+ memcpy(buf, u.buf, MMCSD_BLOCK_SIZE);
+ buf += MMCSD_BLOCK_SIZE;
+ startblk++;
+ }
+ return HAL_SUCCESS;
+ }
+#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer");
+#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ return sdc_lld_read_aligned(sdcp, startblk, buf, blocks);
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] blocks number of blocks to write
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks) {
+
+#if STM32_SDC_SDIO_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < blocks; i++) {
+ memcpy(u.buf, buf, MMCSD_BLOCK_SIZE);
+ buf += MMCSD_BLOCK_SIZE;
+ if (sdc_lld_write_aligned(sdcp, startblk, u.buf, 1))
+ return HAL_FAILED;
+ startblk++;
+ }
+ return HAL_SUCCESS;
+ }
+#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer");
+#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ return sdc_lld_write_aligned(sdcp, startblk, buf, blocks);
+}
+
+/**
+ * @brief Waits for card idle condition.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS the operation succeeded.
+ * @retval HAL_FAILED the operation failed.
+ *
+ * @api
+ */
+bool sdc_lld_sync(SDCDriver *sdcp) {
+
+ /* CHTODO: Implement.*/
+ (void)sdcp;
+ return HAL_SUCCESS;
+}
+
+#endif /* HAL_USE_SDC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h new file mode 100644 index 0000000..4f0a430 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDIOv1/hal_sdc_lld.h @@ -0,0 +1,353 @@ +/*
+ 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 SDIOv1/hal_sdc_lld.h
+ * @brief STM32 SDC subsystem low level driver header.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#ifndef HAL_SDC_LLD_H
+#define HAL_SDC_LLD_H
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*
+ * The following definitions are missing from some implementations, fixing
+ * as zeroed masks.
+ */
+#if !defined(SDIO_STA_STBITERR)
+#define SDIO_STA_STBITERR 0
+#endif
+
+#if !defined(SDIO_ICR_STBITERRC)
+#define SDIO_ICR_STBITERRC 0
+#endif
+
+#if !defined(SDIO_ICR_CEATAENDC)
+#define SDIO_ICR_CEATAENDC 0
+#endif
+
+#if !defined(SDIO_MASK_STBITERRIE)
+#define SDIO_MASK_STBITERRIE 0
+#endif
+
+/**
+ * @brief Value to clear all interrupts flag at once.
+ */
+#define STM32_SDIO_ICR_ALL_FLAGS (SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | \
+ SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC | \
+ SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | \
+ SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | \
+ SDIO_ICR_DATAENDC | SDIO_ICR_STBITERRC | \
+ SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | \
+ SDIO_ICR_CEATAENDC)
+
+/**
+ * @brief Mask of error flags in STA register.
+ */
+#define STM32_SDIO_STA_ERROR_MASK (SDIO_STA_CCRCFAIL | SDIO_STA_DCRCFAIL | \
+ SDIO_STA_CTIMEOUT | SDIO_STA_DTIMEOUT | \
+ SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR)
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SDIO DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_SDC_SDIO_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDIO_DMA_PRIORITY 3
+#endif
+
+/**
+ * @brief SDIO interrupt priority level setting.
+ */
+#if !defined(STM32_SDC_SDIO_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDIO_IRQ_PRIORITY 9
+#endif
+
+/**
+ * @brief Enable clock bypass.
+ * @note Allow clock speed up to 50 Mhz.
+ */
+#if !defined(STM32_SDC_SDIO_50MHZ) || defined(__DOXYGEN__)
+#define STM32_SDC_SDIO_50MHZ FALSE
+#endif
+
+/**
+ * @brief Write timeout in milliseconds.
+ */
+#if !defined(STM32_SDC_WRITE_TIMEOUT_MS) || defined(__DOXYGEN__)
+#define STM32_SDC_WRITE_TIMEOUT_MS 1000
+#endif
+
+/**
+ * @brief Read timeout in milliseconds.
+ */
+#if !defined(STM32_SDC_READ_TIMEOUT_MS) || defined(__DOXYGEN__)
+#define STM32_SDC_READ_TIMEOUT_MS 1000
+#endif
+
+/**
+ * @brief Card clock activation delay in milliseconds.
+ */
+#if !defined(STM32_SDC_CLOCK_ACTIVATION_DELAY) || defined(__DOXYGEN__)
+#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10
+#endif
+
+/**
+ * @brief Support for unaligned transfers.
+ * @note Unaligned transfers are much slower.
+ */
+#if !defined(STM32_SDC_SDIO_UNALIGNED_SUPPORT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !STM32_HAS_SDIO
+#error "SDIO not present in the selected device"
+#endif
+
+#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDIO_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SDIO"
+#endif
+
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDIO_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SDIO"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if !defined(STM32_SDC_SDIO_DMA_STREAM)
+#error "SDIO DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if !STM32_DMA_IS_VALID_ID(STM32_SDC_SDIO_DMA_STREAM, STM32_SDC_SDIO_DMA_MSK)
+#error "invalid DMA stream associated to SDIO"
+#endif
+#endif /* STM32_ADVANCED_DMA */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*
+ * SDIO clock divider.
+ */
+#if (defined(STM32F4XX) || defined(STM32F2XX))
+#define STM32_SDIO_DIV_HS 0
+#define STM32_SDIO_DIV_LS 120
+
+#elif STM32_HCLK > 48000000
+#define STM32_SDIO_DIV_HS 1
+#define STM32_SDIO_DIV_LS 178
+#else
+
+#define STM32_SDIO_DIV_HS 0
+#define STM32_SDIO_DIV_LS 118
+#endif
+
+/**
+ * @brief SDIO data timeouts in SDIO clock cycles.
+ */
+#if (defined(STM32F4XX) || defined(STM32F2XX))
+#if !STM32_CLOCK48_REQUIRED
+#error "SDIO requires STM32_CLOCK48_REQUIRED to be enabled"
+#endif
+
+#if STM32_PLL48CLK != 48000000
+#error "invalid STM32_PLL48CLK clock value"
+#endif
+
+#define STM32_SDC_WRITE_TIMEOUT \
+ (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \
+ STM32_SDC_WRITE_TIMEOUT_MS)
+#define STM32_SDC_READ_TIMEOUT \
+ (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \
+ STM32_SDC_READ_TIMEOUT_MS)
+
+#else /* !(defined(STM32F4XX) || defined(STM32F2XX)) */
+
+#define STM32_SDC_WRITE_TIMEOUT \
+ (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \
+ STM32_SDC_WRITE_TIMEOUT_MS)
+#define STM32_SDC_READ_TIMEOUT \
+ (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \
+ STM32_SDC_READ_TIMEOUT_MS)
+
+#endif /* !(defined(STM32F4XX) || defined(STM32F2XX)) */
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of card flags.
+ */
+typedef uint32_t sdcmode_t;
+
+/**
+ * @brief SDC Driver condition flags type.
+ */
+typedef uint32_t sdcflags_t;
+
+/**
+ * @brief Type of a structure representing an SDC driver.
+ */
+typedef struct SDCDriver SDCDriver;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Bus width.
+ */
+ sdcbusmode_t bus_width;
+ /* End of the mandatory fields.*/
+} SDCConfig;
+
+/**
+ * @brief @p SDCDriver specific methods.
+ */
+#define _sdc_driver_methods \
+ _mmcsd_block_device_methods
+
+/**
+ * @extends MMCSDBlockDeviceVMT
+ *
+ * @brief @p SDCDriver virtual methods table.
+ */
+struct SDCDriverVMT {
+ _sdc_driver_methods
+};
+
+/**
+ * @brief Structure representing an SDC driver.
+ */
+struct SDCDriver {
+ /**
+ * @brief Virtual Methods Table.
+ */
+ const struct SDCDriverVMT *vmt;
+ _mmcsd_block_device_data
+ /**
+ * @brief Current configuration data.
+ */
+ const SDCConfig *config;
+ /**
+ * @brief Various flags regarding the mounted card.
+ */
+ sdcmode_t cardmode;
+ /**
+ * @brief Errors flags.
+ */
+ sdcflags_t errors;
+ /**
+ * @brief Card RCA.
+ */
+ uint32_t rca;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Thread waiting for I/O completion IRQ.
+ */
+ thread_reference_t thread;
+ /**
+ * @brief DMA mode bit mask.
+ */
+ uint32_t dmamode;
+ /**
+ * @brief Transmit DMA channel.
+ */
+ const stm32_dma_stream_t *dma;
+ /**
+ * @brief Pointer to the SDIO registers block.
+ * @note Needed for debugging aid.
+ */
+ SDIO_TypeDef *sdio;
+ /**
+ * @brief Buffer for internal operations.
+ */
+ uint8_t buf[MMCSD_BLOCK_SIZE];
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern SDCDriver SDCD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sdc_lld_init(void);
+ void sdc_lld_start(SDCDriver *sdcp);
+ void sdc_lld_stop(SDCDriver *sdcp);
+ void sdc_lld_start_clk(SDCDriver *sdcp);
+ void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk);
+ void sdc_lld_stop_clk(SDCDriver *sdcp);
+ void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode);
+ void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg);
+ bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes,
+ uint8_t cmd, uint32_t argument);
+ bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks);
+ bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks);
+ bool sdc_lld_sync(SDCDriver *sdcp);
+ bool sdc_lld_is_card_inserted(SDCDriver *sdcp);
+ bool sdc_lld_is_write_protected(SDCDriver *sdcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SDC */
+
+#endif /* HAL_SDC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk new file mode 100644 index 0000000..7edbc24 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c new file mode 100644 index 0000000..1544981 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.c @@ -0,0 +1,981 @@ +/*
+ 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 SDMMCv1/hal_sdc_lld.c
+ * @brief STM32 SDC subsystem low level driver source.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define SDMMC_ICR_ALL_FLAGS \
+ (SDMMC_ICR_CCRCFAILC | SDMMC_ICR_DCRCFAILC | \
+ SDMMC_ICR_CTIMEOUTC | SDMMC_ICR_DTIMEOUTC | \
+ SDMMC_ICR_TXUNDERRC | SDMMC_ICR_RXOVERRC | \
+ SDMMC_ICR_CMDRENDC | SDMMC_ICR_CMDSENTC | \
+ SDMMC_ICR_DATAENDC | SDMMC_ICR_DBCKENDC | \
+ SDMMC_ICR_SDIOITC)
+
+#define SDMMC_STA_ERROR_MASK \
+ (SDMMC_STA_CCRCFAIL | SDMMC_STA_DCRCFAIL | \
+ SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \
+ SDMMC_STA_TXUNDERR | SDMMC_STA_RXOVERR)
+
+#define SDMMC_CLKDIV_HS (2 - 2)
+#define SDMMC_CLKDIV_LS (120 - 2)
+
+#define SDMMC1_WRITE_TIMEOUT \
+ (((STM32_SDMMC1CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \
+ STM32_SDC_SDMMC_WRITE_TIMEOUT)
+#define SDMMC1_READ_TIMEOUT \
+ (((STM32_SDMMC1CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \
+ STM32_SDC_SDMMC_READ_TIMEOUT)
+
+#define SDMMC2_WRITE_TIMEOUT \
+ (((STM32_SDMMC2CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \
+ STM32_SDC_SDMMC_WRITE_TIMEOUT)
+#define SDMMC2_READ_TIMEOUT \
+ (((STM32_SDMMC2CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \
+ STM32_SDC_SDMMC_READ_TIMEOUT)
+
+#define SDMMC1_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SDC_SDMMC1_DMA_STREAM, \
+ STM32_SDC_SDMMC1_DMA_CHN)
+
+#define SDMMC2_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SDC_SDMMC2_DMA_STREAM, \
+ STM32_SDC_SDMMC2_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SDCD1 driver identifier.*/
+#if STM32_SDC_USE_SDMMC1 || defined(__DOXYGEN__)
+SDCDriver SDCD1;
+#endif
+
+/** @brief SDCD2 driver identifier.*/
+#if STM32_SDC_USE_SDMMC2 || defined(__DOXYGEN__)
+SDCDriver SDCD2;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief SDIO default configuration.
+ */
+static const SDCConfig sdc_default_cfg = {
+ SDC_MODE_4BIT
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Prepares to handle read transaction.
+ * @details Designed for read special registers from card.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[out] buf pointer to the read buffer
+ * @param[in] bytes number of bytes to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp,
+ uint8_t *buf, uint32_t bytes) {
+ osalDbgCheck(bytes < 0x1000000);
+
+ sdcp->sdmmc->DTIMER = sdcp->rtmo;
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaStreamSetMemory0(sdcp->dma, buf);
+ dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t));
+ dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M);
+ dmaStreamEnable(sdcp->dma);
+
+ /* Setting up data transfer.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE |
+ SDMMC_MASK_DTIMEOUTIE |
+ SDMMC_MASK_RXOVERRIE |
+ SDMMC_MASK_DATAENDIE;
+ sdcp->sdmmc->DLEN = bytes;
+
+ /* Transaction starts just after DTEN bit setting.*/
+ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR |
+ SDMMC_DCTRL_DTMODE | /* Multibyte data transfer.*/
+ SDMMC_DCTRL_DMAEN |
+ SDMMC_DCTRL_DTEN;
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Prepares card to handle read transaction.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[in] n number of blocks to read
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk,
+ uint32_t n, uint32_t *resp) {
+
+ /* Driver handles data in 512 bytes blocks (just like HC cards). But if we
+ have not HC card than we must convert address from blocks to bytes.*/
+ if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY))
+ startblk *= MMCSD_BLOCK_SIZE;
+
+ if (n > 1) {
+ /* Send read multiple blocks command to card.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+ else {
+ /* Send read single block command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Prepares card to handle write transaction.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[in] n number of blocks to write
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk,
+ uint32_t n, uint32_t *resp) {
+
+ /* Driver handles data in 512 bytes blocks (just like HC cards). But if we
+ have not HC card than we must convert address from blocks to bytes.*/
+ if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY))
+ startblk *= MMCSD_BLOCK_SIZE;
+
+ if (n > 1) {
+ /* Write multiple blocks command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+ else {
+ /* Write single block command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Wait end of data transaction and performs finalizations.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] n number of blocks in transaction
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ */
+static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n,
+ uint32_t *resp) {
+
+ /* Note the mask is checked before going to sleep because the interrupt
+ may have occurred before reaching the critical zone.*/
+ osalSysLock();
+ if (sdcp->sdmmc->MASK != 0)
+ osalThreadSuspendS(&sdcp->thread);
+ if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) {
+ osalSysUnlock();
+ return HAL_FAILED;
+ }
+
+ /* Waits for transfer completion at DMA level, then the stream is
+ disabled and cleared.*/
+ dmaWaitCompletion(sdcp->dma);
+
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->DCTRL = 0;
+ osalSysUnlock();
+
+ /* Finalize transaction.*/
+ if (n > 1)
+ return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Gets SDC errors.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] sta value of the STA register
+ *
+ * @notapi
+ */
+static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) {
+ uint32_t errors = SDC_NO_ERROR;
+
+ if (sta & SDMMC_STA_CCRCFAIL)
+ errors |= SDC_CMD_CRC_ERROR;
+ if (sta & SDMMC_STA_DCRCFAIL)
+ errors |= SDC_DATA_CRC_ERROR;
+ if (sta & SDMMC_STA_CTIMEOUT)
+ errors |= SDC_COMMAND_TIMEOUT;
+ if (sta & SDMMC_STA_DTIMEOUT)
+ errors |= SDC_DATA_TIMEOUT;
+ if (sta & SDMMC_STA_TXUNDERR)
+ errors |= SDC_TX_UNDERRUN;
+ if (sta & SDMMC_STA_RXOVERR)
+ errors |= SDC_RX_OVERRUN;
+/* if (sta & SDMMC_STA_STBITERR)
+ errors |= SDC_STARTBIT_ERROR;*/
+
+ sdcp->errors |= errors;
+}
+
+/**
+ * @brief Performs clean transaction stopping in case of errors.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] n number of blocks in transaction
+ * @param[in] resp pointer to the response buffer
+ *
+ * @notapi
+ */
+static void sdc_lld_error_cleanup(SDCDriver *sdcp,
+ uint32_t n,
+ uint32_t *resp) {
+ uint32_t sta = sdcp->sdmmc->STA;
+
+ dmaStreamDisable(sdcp->dma);
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = 0;
+ sdcp->sdmmc->DCTRL = 0;
+ sdc_lld_collect_errors(sdcp, sta);
+
+ if (n > 1)
+ sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief SDMMC1 IRQ handler.
+ * @details It just wakes transaction thread, errors handling is performed in
+ * there.
+ *
+ * @isr
+ */
+#if STM32_SDC_USE_SDMMC1 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(STM32_SDMMC1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ osalSysLockFromISR();
+
+ /* Disables the source but the status flags are not reset because the
+ read/write functions needs to check them.*/
+ SDMMC1->MASK = 0;
+
+ osalThreadResumeI(&SDCD1.thread, MSG_OK);
+
+ osalSysUnlockFromISR();
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/**
+ * @brief SDMMC2 IRQ handler.
+ * @details It just wakes transaction thread, errors handling is performed in
+ * there.
+ *
+ * @isr
+ */
+#if STM32_SDC_USE_SDMMC2 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(STM32_SDMMC2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ osalSysLockFromISR();
+
+ /* Disables the source but the status flags are not reset because the
+ read/write functions needs to check them.*/
+ SDMMC2->MASK = 0;
+
+ osalThreadResumeI(&SDCD2.thread, MSG_OK);
+
+ osalSysUnlockFromISR();
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SDC driver initialization.
+ *
+ * @notapi
+ */
+void sdc_lld_init(void) {
+
+#if STM32_SDC_USE_SDMMC1
+ sdcObjectInit(&SDCD1);
+ SDCD1.thread = NULL;
+ SDCD1.rtmo = SDMMC1_READ_TIMEOUT;
+ SDCD1.wtmo = SDMMC1_WRITE_TIMEOUT;
+ SDCD1.dma = NULL;
+ SDCD1.sdmmc = SDMMC1;
+ nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_SDC_SDMMC1_IRQ_PRIORITY);
+#endif
+
+#if STM32_SDC_USE_SDMMC2
+ sdcObjectInit(&SDCD2);
+ SDCD2.thread = NULL;
+ SDCD2.rtmo = SDMMC2_READ_TIMEOUT;
+ SDCD2.wtmo = SDMMC2_WRITE_TIMEOUT;
+ SDCD2.dma = NULL;
+ SDCD2.sdmmc = SDMMC2;
+ nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_SDC_SDMMC2_IRQ_PRIORITY);
+#endif
+}
+
+/**
+ * @brief Configures and activates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start(SDCDriver *sdcp) {
+
+ /* Checking configuration, using a default if NULL has been passed.*/
+ if (sdcp->config == NULL) {
+ sdcp->config = &sdc_default_cfg;
+ }
+
+ sdcp->dmamode = STM32_DMA_CR_PSIZE_WORD |
+ STM32_DMA_CR_MSIZE_WORD |
+ STM32_DMA_CR_MINC;
+
+#if STM32_DMA_ADVANCED
+ sdcp->dmamode |= STM32_DMA_CR_PFCTRL |
+ STM32_DMA_CR_PBURST_INCR4 |
+ STM32_DMA_CR_MBURST_INCR4;
+#endif
+
+ /* If in stopped state then clocks are enabled and DMA initialized.*/
+ if (sdcp->state == BLK_STOP) {
+#if STM32_SDC_USE_SDMMC1
+ if (&SDCD1 == sdcp) {
+ sdcp->dma = dmaStreamAllocI(STM32_SDC_SDMMC1_DMA_STREAM,
+ STM32_SDC_SDMMC1_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(sdcp->dma != NULL, "unable to allocate stream");
+
+ sdcp->dmamode |= STM32_DMA_CR_CHSEL(SDMMC1_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SDC_SDMMC1_DMA_PRIORITY);
+ dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdmmc->FIFO);
+#if STM32_DMA_ADVANCED
+ dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS |
+ STM32_DMA_FCR_FTH_FULL);
+#endif
+ rccEnableSDMMC1(true);
+ }
+#endif /* STM32_SDC_USE_SDMMC1 */
+
+#if STM32_SDC_USE_SDMMC2
+ if (&SDCD2 == sdcp) {
+ sdcp->dma = dmaStreamAllocI(STM32_SDC_SDMMC2_DMA_STREAM,
+ STM32_SDC_SDMMC2_IRQ_PRIORITY,
+ NULL,
+ NULL);
+ osalDbgAssert(sdcp->dma != NULL, "unable to allocate stream");
+
+ sdcp->dmamode |= STM32_DMA_CR_CHSEL(SDMMC2_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SDC_SDMMC2_DMA_PRIORITY);
+ dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdmmc->FIFO);
+#if STM32_DMA_ADVANCED
+ dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS |
+ STM32_DMA_FCR_FTH_FULL);
+#endif
+ rccEnableSDMMC2(true);
+ }
+#endif /* STM32_SDC_USE_SDMMC2 */
+ }
+
+ /* Configuration, card clock is initially stopped.*/
+ sdcp->sdmmc->POWER = 0;
+ sdcp->sdmmc->CLKCR = 0;
+ sdcp->sdmmc->DCTRL = 0;
+ sdcp->sdmmc->DTIMER = 0;
+}
+
+/**
+ * @brief Deactivates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop(SDCDriver *sdcp) {
+
+ if (sdcp->state != BLK_STOP) {
+
+ /* SDIO deactivation.*/
+ sdcp->sdmmc->POWER = 0;
+ sdcp->sdmmc->CLKCR = 0;
+ sdcp->sdmmc->DCTRL = 0;
+ sdcp->sdmmc->DTIMER = 0;
+
+ /* DMA stream released.*/
+ dmaStreamFreeI(sdcp->dma);
+ sdcp->dma = NULL;
+
+ /* Clock deactivation.*/
+#if STM32_SDC_USE_SDMMC1
+ if (&SDCD1 == sdcp) {
+ rccDisableSDMMC1();
+ }
+#endif
+
+#if STM32_SDC_USE_SDMMC2
+ if (&SDCD2 == sdcp) {
+ rccDisableSDMMC2();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts the SDIO clock and sets it to init mode (400kHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start_clk(SDCDriver *sdcp) {
+
+ /* Initial clock setting: 400kHz, 1bit mode.*/
+ sdcp->sdmmc->CLKCR = SDMMC_CLKDIV_LS;
+ sdcp->sdmmc->POWER |= SDMMC_POWER_PWRCTRL_0 | SDMMC_POWER_PWRCTRL_1;
+ sdcp->sdmmc->CLKCR |= SDMMC_CLKCR_CLKEN;
+
+ /* Clock activation delay.*/
+ osalThreadSleep(OSAL_MS2I(STM32_SDC_SDMMC_CLOCK_DELAY));
+}
+
+/**
+ * @brief Sets the SDIO clock to data mode (25/50 MHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] clk the clock mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) {
+
+#if STM32_SDC_SDMMC_50MHZ
+ if (SDC_CLK_50MHz == clk) {
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
+#if STM32_SDC_SDMMC_PWRSAV
+ SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS |
+ SDMMC_CLKCR_PWRSAV;
+#else
+ SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS;
+#endif
+ }
+ else {
+#if STM32_SDC_SDMMC_PWRSAV
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS |
+ SDMMC_CLKCR_PWRSAV;
+#else
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS;
+#endif
+ }
+#else
+ (void)clk;
+
+#if STM32_SDC_SDMMC_PWRSAV
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS |
+ SDMMC_CLKCR_PWRSAV;
+#else
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS;
+#endif
+#endif
+}
+
+/**
+ * @brief Stops the SDIO clock.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop_clk(SDCDriver *sdcp) {
+
+ sdcp->sdmmc->CLKCR = 0;
+ sdcp->sdmmc->POWER = 0;
+}
+
+/**
+ * @brief Switches the bus to 1, 4 or 8 bits mode.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] mode bus mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) {
+ uint32_t clk = sdcp->sdmmc->CLKCR & ~SDMMC_CLKCR_WIDBUS;
+
+ switch (mode) {
+ case SDC_MODE_1BIT:
+ sdcp->sdmmc->CLKCR = clk;
+ break;
+ case SDC_MODE_4BIT:
+ sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_0;
+ break;
+ case SDC_MODE_8BIT:
+ sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_1;
+ break;
+ }
+}
+
+/**
+ * @brief Sends an SDIO command with no response expected.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ *
+ * @notapi
+ */
+void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) {
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_CPSMEN;
+ while ((sdcp->sdmmc->STA & SDMMC_STA_CMDSENT) == 0)
+ ;
+ sdcp->sdmmc->ICR = SDMMC_ICR_CMDSENTC;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected.
+ * @note The CRC is not verified.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN;
+ while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL);
+ if ((sta & (SDMMC_STA_CTIMEOUT)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ *resp = sdcp->sdmmc->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN;
+ while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT | SDMMC_STA_CCRCFAIL);
+ if ((sta & (SDMMC_STA_CTIMEOUT | SDMMC_STA_CCRCFAIL)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ *resp = sdcp->sdmmc->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Sends an SDIO command with a long response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (four words)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ (void)sdcp;
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_WAITRESP_1 |
+ SDMMC_CMD_CPSMEN;
+ while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL);
+ if ((sta & (SDMMC_STA_ERROR_MASK)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ /* Save bytes in reverse order because MSB in response comes first.*/
+ *resp++ = sdcp->sdmmc->RESP4;
+ *resp++ = sdcp->sdmmc->RESP3;
+ *resp++ = sdcp->sdmmc->RESP2;
+ *resp = sdcp->sdmmc->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Reads special registers using data bus.
+ * @details Needs only during card detection procedure.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[out] buf pointer to the read buffer
+ * @param[in] bytes number of bytes to read
+ * @param[in] cmd card command
+ * @param[in] arg argument for command
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes,
+ uint8_t cmd, uint32_t arg) {
+ uint32_t resp[1];
+
+ if (sdc_lld_prepare_read_bytes(sdcp, buf, bytes))
+ goto error;
+
+ if (sdc_lld_send_cmd_short_crc(sdcp, cmd, arg, resp)
+ || MMCSD_R1_ERROR(resp[0]))
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, 1, resp))
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, 1, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] blocks number of blocks to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks) {
+ uint32_t resp[1];
+
+ osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE);
+
+ sdcp->sdmmc->DTIMER = sdcp->rtmo;
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaStreamSetMemory0(sdcp->dma, buf);
+ dmaStreamSetTransactionSize(sdcp->dma,
+ (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t));
+ dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M);
+ dmaStreamEnable(sdcp->dma);
+
+ /* Setting up data transfer.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE |
+ SDMMC_MASK_DTIMEOUTIE |
+ SDMMC_MASK_RXOVERRIE |
+ SDMMC_MASK_DATAENDIE;
+ sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE;
+
+ /* Transaction starts just after DTEN bit setting.*/
+ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR |
+ SDMMC_DCTRL_DBLOCKSIZE_3 |
+ SDMMC_DCTRL_DBLOCKSIZE_0 |
+ SDMMC_DCTRL_DMAEN |
+ SDMMC_DCTRL_DTEN;
+
+ if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true)
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, blocks, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] n number of blocks to write
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks) {
+ uint32_t resp[1];
+
+ osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE);
+
+ sdcp->sdmmc->DTIMER = sdcp->wtmo;
+
+ /* Checks for errors and waits for the card to be ready for writing.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaStreamSetMemory0(sdcp->dma, buf);
+ dmaStreamSetTransactionSize(sdcp->dma,
+ (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t));
+ dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P);
+ dmaStreamEnable(sdcp->dma);
+
+ /* Setting up data transfer.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE |
+ SDMMC_MASK_DTIMEOUTIE |
+ SDMMC_MASK_TXUNDERRIE |
+ SDMMC_MASK_DATAENDIE;
+ sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE;
+
+ /* Talk to card what we want from it.*/
+ if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == true)
+ goto error;
+
+ /* Transaction starts just after DTEN bit setting.*/
+ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DBLOCKSIZE_3 |
+ SDMMC_DCTRL_DBLOCKSIZE_0 |
+ SDMMC_DCTRL_DMAEN |
+ SDMMC_DCTRL_DTEN;
+
+ if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, blocks, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] blocks number of blocks to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks) {
+
+#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < blocks; i++) {
+ if (sdc_lld_read_aligned(sdcp, startblk, sdcp->buf, 1))
+ return HAL_FAILED;
+ memcpy(buf, sdcp->buf, MMCSD_BLOCK_SIZE);
+ buf += MMCSD_BLOCK_SIZE;
+ startblk++;
+ }
+ return HAL_SUCCESS;
+ }
+#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer");
+#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ return sdc_lld_read_aligned(sdcp, startblk, buf, blocks);
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] blocks number of blocks to write
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks) {
+
+#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < blocks; i++) {
+ memcpy(sdcp->buf, buf, MMCSD_BLOCK_SIZE);
+ buf += MMCSD_BLOCK_SIZE;
+ if (sdc_lld_write_aligned(sdcp, startblk, sdcp->buf, 1))
+ return HAL_FAILED;
+ startblk++;
+ }
+ return HAL_SUCCESS;
+ }
+#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer");
+#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ return sdc_lld_write_aligned(sdcp, startblk, buf, blocks);
+}
+
+/**
+ * @brief Waits for card idle condition.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS the operation succeeded.
+ * @retval HAL_FAILED the operation failed.
+ *
+ * @api
+ */
+bool sdc_lld_sync(SDCDriver *sdcp) {
+
+ /* CHTODO: Implement.*/
+ (void)sdcp;
+ return HAL_SUCCESS;
+}
+
+#endif /* HAL_USE_SDC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h new file mode 100644 index 0000000..b9ad69c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv1/hal_sdc_lld.h @@ -0,0 +1,400 @@ +/*
+ 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 SDMMCv1/hal_sdc_lld.h
+ * @brief STM32 SDC subsystem low level driver header.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#ifndef HAL_SDC_LLD_H
+#define HAL_SDC_LLD_H
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SDMMC1 driver enable switch.
+ * @details If set to @p TRUE the support for SDMMC1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SDC_USE_SDMMC1) || defined(__DOXYGEN__)
+#define STM32_SDC_USE_SDMMC1 FALSE
+#endif
+
+/**
+ * @brief SDMMC2 driver enable switch.
+ * @details If set to @p TRUE the support for SDMMC2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SDC_USE_SDMMC2) || defined(__DOXYGEN__)
+#define STM32_SDC_USE_SDMMC2 FALSE
+#endif
+
+/**
+ * @brief Support for unaligned transfers.
+ * @note Unaligned transfers are much slower.
+ */
+#if !defined(STM32_SDC_SDMMC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE
+#endif
+
+/**
+ * @brief Enable clock bypass.
+ * @note Allow clock speed up to 50 Mhz.
+ */
+#if !defined(STM32_SDC_SDMMC_50MHZ) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_50MHZ FALSE
+#endif
+
+/**
+ * @brief Write timeout in milliseconds.
+ */
+#if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000
+#endif
+
+/**
+ * @brief Read timeout in milliseconds.
+ */
+#if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_READ_TIMEOUT 1000
+#endif
+
+/**
+ * @brief Card clock activation delay in milliseconds.
+ */
+#if !defined(STM32_SDC_SDMMC_CLOCK_DELAY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_CLOCK_DELAY 10
+#endif
+
+/**
+ * @brief Card clock power saving enable.
+ */
+#if !defined(STM32_SDC_SDMMC_PWRSAV) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_PWRSAV TRUE
+#endif
+
+/**
+ * @brief SDMMC1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_SDC_SDMMC1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC1_DMA_PRIORITY 3
+#endif
+
+/**
+ * @brief SDMMC2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_SDC_SDMMC2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC2_DMA_PRIORITY 3
+#endif
+
+/**
+ * @brief SDMMC1 interrupt priority level setting.
+ */
+#if !defined(STM32_SDC_SDMMC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC1_IRQ_PRIORITY 9
+#endif
+
+/**
+ * @brief SDMMC2 interrupt priority level setting.
+ */
+#if !defined(STM32_SDC_SDMMC2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC2_IRQ_PRIORITY 9
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Registry checks.*/
+#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_HANDLER)) || \
+ (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_HANDLER))
+#error "STM32_SDMMCx_HANDLER not defined in registry"
+#endif
+
+#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_NUMBER)) || \
+ (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_NUMBER))
+#error "STM32_SDMMCx_NUMBER not defined in registry"
+#endif
+
+#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDC_SDMMC1_DMA_MSK)) || \
+ (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDC_SDMMC2_DMA_MSK))
+#error "STM32_SDC_SDMMCx_DMA_MSK not defined in registry"
+#endif
+
+#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDC_SDMMC1_DMA_CHN)) || \
+ (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDC_SDMMC2_DMA_CHN))
+#error "STM32_SDC_SDMMCx_DMA_CHN not defined in registry"
+#endif
+
+/* Units checks.*/
+#if STM32_SDC_USE_SDMMC1 && !STM32_HAS_SDMMC1
+#error "SDMMC1 not present in the selected device"
+#endif
+
+#if STM32_SDC_USE_SDMMC2 && !STM32_HAS_SDMMC2
+#error "SDMMC2 not present in the selected device"
+#endif
+
+#if !STM32_SDC_USE_SDMMC1 && !STM32_SDC_USE_SDMMC2
+#error "SDC driver activated but no SDMMC peripheral assigned"
+#endif
+
+/* Clock related tests.*/
+#if STM32_HAS_SDMMC1 && !defined(STM32_SDMMC1CLK)
+#error "STM32_SDMMC1CLK not defined"
+#endif
+
+/* Clock related tests.*/
+#if STM32_HAS_SDMMC2 && !defined(STM32_SDMMC2CLK)
+#error "STM32_SDMMC2CLK not defined"
+#endif
+
+#if !defined(STM32_HCLK)
+#error "STM32_HCLK not defined"
+#endif
+
+#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK * 10 > STM32_HCLK * 7)
+#error "STM32_SDMMC1CLK must not exceed STM32_HCLK * 0.7"
+#endif
+
+#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK * 10 > STM32_HCLK * 7)
+#error "STM32_SDMMC2CLK must not exceed STM32_HCLK * 0.7"
+#endif
+
+#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK > 48000000)
+#error "STM32_SDMMC1CLK must not exceed 48MHz"
+#endif
+
+#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK > 48000000)
+#error "STM32_SDMMC2CLK must not exceed 48MHz"
+#endif
+
+#if defined(STM32_SDC_SDMMC_50MHZ) && STM32_SDC_SDMMC_50MHZ && !defined(STM32F7XX)
+#error "50 Mhz clock only works for STM32F7XX"
+#endif
+
+/* SDMMC IRQ priority tests.*/
+#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDMMC1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SDMMC1"
+#endif
+
+#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDMMC2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SDMMC2"
+#endif
+
+/* DMA priority tests.*/
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDMMC1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SDMMC1"
+#endif
+
+#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDMMC2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SDMMC2"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_SDC_USE_SDMMC1 && !defined(STM32_SDC_SDMMC1_DMA_STREAM)
+#error "SDMMC1 DMA streams not defined"
+#endif
+
+#if STM32_SDC_USE_SDMMC2 && !defined(STM32_SDC_SDMMC2_DMA_STREAM)
+#error "SDMMC2 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_SDC_USE_SDMMC1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SDC_SDMMC1_DMA_STREAM, STM32_SDC_SDMMC1_DMA_MSK)
+#error "invalid DMA stream associated to SDMMC1"
+#endif
+
+#if STM32_SDC_USE_SDMMC2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SDC_SDMMC2_DMA_STREAM, STM32_SDC_SDMMC2_DMA_MSK)
+#error "invalid DMA stream associated to SDMMC2"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of card flags.
+ */
+typedef uint32_t sdcmode_t;
+
+/**
+ * @brief SDC Driver condition flags type.
+ */
+typedef uint32_t sdcflags_t;
+
+/**
+ * @brief Type of a structure representing an SDC driver.
+ */
+typedef struct SDCDriver SDCDriver;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Bus width.
+ */
+ sdcbusmode_t bus_width;
+ /* End of the mandatory fields.*/
+} SDCConfig;
+
+/**
+ * @brief @p SDCDriver specific methods.
+ */
+#define _sdc_driver_methods \
+ _mmcsd_block_device_methods
+
+/**
+ * @extends MMCSDBlockDeviceVMT
+ *
+ * @brief @p SDCDriver virtual methods table.
+ */
+struct SDCDriverVMT {
+ _sdc_driver_methods
+};
+
+/**
+ * @brief Structure representing an SDC driver.
+ */
+struct SDCDriver {
+ /**
+ * @brief Virtual Methods Table.
+ */
+ const struct SDCDriverVMT *vmt;
+ _mmcsd_block_device_data
+ /**
+ * @brief Current configuration data.
+ */
+ const SDCConfig *config;
+ /**
+ * @brief Various flags regarding the mounted card.
+ */
+ sdcmode_t cardmode;
+ /**
+ * @brief Errors flags.
+ */
+ sdcflags_t errors;
+ /**
+ * @brief Card RCA.
+ */
+ uint32_t rca;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Thread waiting for I/O completion IRQ.
+ */
+ thread_reference_t thread;
+ /**
+ * @brief DTIMER register value for read operations.
+ */
+ uint32_t rtmo;
+ /**
+ * @brief DTIMER register value for write operations.
+ */
+ uint32_t wtmo;
+ /**
+ * @brief DMA mode bit mask.
+ */
+ uint32_t dmamode;
+ /**
+ * @brief Transmit DMA channel.
+ */
+ const stm32_dma_stream_t *dma;
+ /**
+ * @brief Pointer to the SDMMC registers block.
+ * @note Needed for debugging aid.
+ */
+ SDMMC_TypeDef *sdmmc;
+ /**
+ * @brief Buffer for internal operations.
+ */
+ uint8_t buf[MMCSD_BLOCK_SIZE];
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SDC_USE_SDMMC1 && !defined(__DOXYGEN__)
+extern SDCDriver SDCD1;
+#endif
+
+#if STM32_SDC_USE_SDMMC2 && !defined(__DOXYGEN__)
+extern SDCDriver SDCD2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sdc_lld_init(void);
+ void sdc_lld_start(SDCDriver *sdcp);
+ void sdc_lld_stop(SDCDriver *sdcp);
+ void sdc_lld_start_clk(SDCDriver *sdcp);
+ void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk);
+ void sdc_lld_stop_clk(SDCDriver *sdcp);
+ void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode);
+ void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg);
+ bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes,
+ uint8_t cmd, uint32_t argument);
+ bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks);
+ bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks);
+ bool sdc_lld_sync(SDCDriver *sdcp);
+ bool sdc_lld_is_card_inserted(SDCDriver *sdcp);
+ bool sdc_lld_is_write_protected(SDCDriver *sdcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SDC */
+
+#endif /* HAL_SDC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk new file mode 100644 index 0000000..cf8b9d2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c new file mode 100644 index 0000000..9740df2 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c @@ -0,0 +1,865 @@ +/*
+ 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 SDMMCv2/hal_sdc_lld.c
+ * @brief STM32 SDC subsystem low level driver source.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define SDMMC_ICR_ALL_FLAGS 0xFFFFFFFFU
+
+#define SDMMC_STA_ERROR_MASK \
+ (SDMMC_STA_CCRCFAIL | SDMMC_STA_DCRCFAIL | \
+ SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \
+ SDMMC_STA_TXUNDERR | SDMMC_STA_RXOVERR)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SDCD1 driver identifier.*/
+#if STM32_SDC_USE_SDMMC1 || defined(__DOXYGEN__)
+SDCDriver SDCD1;
+#endif
+
+/** @brief SDCD2 driver identifier.*/
+#if STM32_SDC_USE_SDMMC2 || defined(__DOXYGEN__)
+SDCDriver SDCD2;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief SDIO default configuration.
+ */
+static const SDCConfig sdc_default_cfg = {
+ SDC_MODE_4BIT
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Calculates a clock divider for the specified frequency.
+ * @note The divider is calculated to not exceed the required frequency
+ * in case of non-integer division.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] f required frequency
+ */
+static uint32_t sdc_lld_clkdiv(SDCDriver *sdcp, uint32_t f) {
+
+ if (f >= sdcp->clkfreq) {
+ return 0;
+ }
+
+ return (sdcp->clkfreq + (f * 2) - 1) / (f * 2);
+}
+
+/**
+ * @brief Prepares to handle read transaction.
+ * @details Designed for read special registers from card.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[out] buf pointer to the read buffer
+ * @param[in] bytes number of bytes to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp,
+ uint8_t *buf, uint32_t bytes) {
+ osalDbgCheck(bytes < 0x1000000);
+
+ sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_READ_TIMEOUT;
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Setting up data transfer.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE |
+ SDMMC_MASK_DTIMEOUTIE |
+ SDMMC_MASK_RXOVERRIE |
+ SDMMC_MASK_DATAENDIE;
+ sdcp->sdmmc->DLEN = bytes;
+
+ /* Transfer modes.*/
+ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR |
+ SDMMC_DCTRL_DTMODE_0; /* Multibyte data transfer.*/
+
+ /* Prepares IDMA.*/
+ sdcp->sdmmc->IDMABASE0 = (uint32_t)buf;
+ sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN;
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Prepares card to handle read transaction.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[in] n number of blocks to read
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk,
+ uint32_t n, uint32_t *resp) {
+
+ /* Driver handles data in 512 bytes blocks (just like HC cards). But if we
+ have not HC card than we must convert address from blocks to bytes.*/
+ if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY))
+ startblk *= MMCSD_BLOCK_SIZE;
+
+ if (n > 1) {
+ /* Send read multiple blocks command to card.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_READ_MULTIPLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+ else {
+ /* Send read single block command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_READ_SINGLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Prepares card to handle write transaction.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[in] n number of blocks to write
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk,
+ uint32_t n, uint32_t *resp) {
+
+ /* Driver handles data in 512 bytes blocks (just like HC cards). But if we
+ have not HC card than we must convert address from blocks to bytes.*/
+ if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY))
+ startblk *= MMCSD_BLOCK_SIZE;
+
+ if (n > 1) {
+ /* Write multiple blocks command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_WRITE_MULTIPLE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+ else {
+ /* Write single block command.*/
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_WRITE_BLOCK,
+ startblk, resp) || MMCSD_R1_ERROR(resp[0]))
+ return HAL_FAILED;
+ }
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Wait end of data transaction and performs finalizations.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] n number of blocks in transaction
+ * @param[in] resp pointer to the response buffer
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ */
+static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n,
+ uint32_t *resp) {
+
+ /* Note the mask is checked before going to sleep because the interrupt
+ may have occurred before reaching the critical zone.*/
+ osalSysLock();
+ if (sdcp->sdmmc->MASK != 0)
+ osalThreadSuspendS(&sdcp->thread);
+
+ /* Stopping operations.*/
+ sdcp->sdmmc->IDMACTRL = 0;
+ sdcp->sdmmc->MASK = 0;
+ sdcp->sdmmc->DCTRL = 0;
+
+ if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) {
+ osalSysUnlock();
+ return HAL_FAILED;
+ }
+
+ /* Clearing status.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ osalSysUnlock();
+
+ /* Finalize transaction.*/
+ if (n > 1)
+ return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);
+
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Gets SDC errors.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] sta value of the STA register
+ *
+ * @notapi
+ */
+static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) {
+ uint32_t errors = SDC_NO_ERROR;
+
+ if (sta & SDMMC_STA_CCRCFAIL)
+ errors |= SDC_CMD_CRC_ERROR;
+ if (sta & SDMMC_STA_DCRCFAIL)
+ errors |= SDC_DATA_CRC_ERROR;
+ if (sta & SDMMC_STA_CTIMEOUT)
+ errors |= SDC_COMMAND_TIMEOUT;
+ if (sta & SDMMC_STA_DTIMEOUT)
+ errors |= SDC_DATA_TIMEOUT;
+ if (sta & SDMMC_STA_TXUNDERR)
+ errors |= SDC_TX_UNDERRUN;
+ if (sta & SDMMC_STA_RXOVERR)
+ errors |= SDC_RX_OVERRUN;
+/* if (sta & SDMMC_STA_STBITERR)
+ errors |= SDC_STARTBIT_ERROR;*/
+
+ sdcp->errors |= errors;
+}
+
+/**
+ * @brief Performs clean transaction stopping in case of errors.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] n number of blocks in transaction
+ * @param[in] resp pointer to the response buffer
+ *
+ * @notapi
+ */
+static void sdc_lld_error_cleanup(SDCDriver *sdcp,
+ uint32_t n,
+ uint32_t *resp) {
+ uint32_t sta = sdcp->sdmmc->STA;
+
+ /* Clearing status.*/
+ sta = sdcp->sdmmc->STA;
+ sdcp->sdmmc->ICR = sta;
+ sdc_lld_collect_errors(sdcp, sta);
+
+ if (n > 1)
+ sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SDC driver initialization.
+ *
+ * @notapi
+ */
+void sdc_lld_init(void) {
+
+#if STM32_SDC_USE_SDMMC1
+ sdcObjectInit(&SDCD1);
+ SDCD1.thread = NULL;
+ SDCD1.sdmmc = SDMMC1;
+ SDCD1.clkfreq = STM32_SDMMC1CLK;
+#endif
+
+#if STM32_SDC_USE_SDMMC2
+ sdcObjectInit(&SDCD2);
+ SDCD2.thread = NULL;
+ SDCD2.sdmmc = SDMMC2;
+ SDCD2.clkfreq = STM32_SDMMC2CLK;
+#endif
+}
+
+/**
+ * @brief Configures and activates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start(SDCDriver *sdcp) {
+
+ /* Checking configuration, using a default if NULL has been passed.*/
+ if (sdcp->config == NULL) {
+ sdcp->config = &sdc_default_cfg;
+ }
+
+ /* If in stopped state then clocks are enabled and DMA initialized.*/
+ if (sdcp->state == BLK_STOP) {
+#if STM32_SDC_USE_SDMMC1
+ if (&SDCD1 == sdcp) {
+ rccEnableSDMMC1(true);
+ }
+#endif /* STM32_SDC_USE_SDMMC1 */
+
+#if STM32_SDC_USE_SDMMC2
+ if (&SDCD2 == sdcp) {
+ rccEnableSDMMC2(true);
+ }
+#endif /* STM32_SDC_USE_SDMMC2 */
+ }
+
+ /* Configuration, card clock is initially stopped.*/
+ sdcp->sdmmc->IDMACTRL = 0;
+ sdcp->sdmmc->DCTRL = 0;
+ sdcp->sdmmc->POWER = 0;
+ sdcp->sdmmc->CLKCR = 0;
+ sdcp->sdmmc->DTIMER = 0;
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+}
+
+/**
+ * @brief Deactivates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop(SDCDriver *sdcp) {
+
+ if (sdcp->state != BLK_STOP) {
+
+ /* SDIO deactivation.*/
+ sdcp->sdmmc->IDMACTRL = 0;
+ sdcp->sdmmc->DCTRL = 0;
+ sdcp->sdmmc->POWER = 0;
+ sdcp->sdmmc->CLKCR = 0;
+ sdcp->sdmmc->DTIMER = 0;
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+
+ /* Clock deactivation.*/
+#if STM32_SDC_USE_SDMMC1
+ if (&SDCD1 == sdcp) {
+ rccDisableSDMMC1();
+ }
+#endif
+
+#if STM32_SDC_USE_SDMMC2
+ if (&SDCD2 == sdcp) {
+ rccDisableSDMMC2();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts the SDIO clock and sets it to init mode (400kHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start_clk(SDCDriver *sdcp) {
+
+ /* Initial clock setting: 400kHz, 1bit mode.*/
+ sdcp->sdmmc->CLKCR = sdc_lld_clkdiv(sdcp, 4000000);
+ sdcp->sdmmc->POWER |= SDMMC_POWER_PWRCTRL_0 | SDMMC_POWER_PWRCTRL_1;
+/* TODO sdcp->sdmmc->CLKCR |= SDMMC_CLKCR_CLKEN;*/
+
+ /* Clock activation delay.*/
+ osalThreadSleep(OSAL_MS2I(STM32_SDC_SDMMC_CLOCK_DELAY));
+}
+
+/**
+ * @brief Sets the SDIO clock to data mode (25/50 MHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] clk the clock mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) {
+
+ if (SDC_CLK_50MHz == clk) {
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
+#if STM32_SDC_SDMMC_PWRSAV
+ sdc_lld_clkdiv(sdcp, 50000000) | SDMMC_CLKCR_PWRSAV;
+#else
+ sdc_lld_clkdiv(sdcp, 50000000);
+#endif
+ }
+ else {
+#if STM32_SDC_SDMMC_PWRSAV
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
+ sdc_lld_clkdiv(sdcp, 25000000) | SDMMC_CLKCR_PWRSAV;
+#else
+ sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
+ sdc_lld_clkdiv(sdcp, 25000000);
+#endif
+ }
+}
+
+/**
+ * @brief Stops the SDIO clock.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop_clk(SDCDriver *sdcp) {
+
+ sdcp->sdmmc->CLKCR = 0;
+ sdcp->sdmmc->POWER = 0;
+}
+
+/**
+ * @brief Switches the bus to 1, 4 or 8 bits mode.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] mode bus mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) {
+ uint32_t clk = sdcp->sdmmc->CLKCR & ~SDMMC_CLKCR_WIDBUS;
+
+ switch (mode) {
+ case SDC_MODE_1BIT:
+ sdcp->sdmmc->CLKCR = clk;
+ break;
+ case SDC_MODE_4BIT:
+ sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_0;
+ break;
+ case SDC_MODE_8BIT:
+ sdcp->sdmmc->CLKCR = clk | SDMMC_CLKCR_WIDBUS_1;
+ break;
+ }
+}
+
+/**
+ * @brief Sends an SDIO command with no response expected.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ *
+ * @notapi
+ */
+void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) {
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_CPSMEN;
+ while ((sdcp->sdmmc->STA & SDMMC_STA_CMDSENT) == 0)
+ ;
+ sdcp->sdmmc->ICR = SDMMC_ICR_CMDSENTC;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected.
+ * @note The CRC is not verified.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN;
+ while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL);
+ if ((sta & (SDMMC_STA_CTIMEOUT)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ *resp = sdcp->sdmmc->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_CPSMEN;
+ while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL);
+ if ((sta & (SDMMC_STA_CTIMEOUT | SDMMC_STA_CCRCFAIL)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ *resp = sdcp->sdmmc->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Sends an SDIO command with a long response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (four words)
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ (void)sdcp;
+
+ sdcp->sdmmc->ARG = arg;
+ sdcp->sdmmc->CMD = (uint32_t)cmd | SDMMC_CMD_WAITRESP_0 | SDMMC_CMD_WAITRESP_1 |
+ SDMMC_CMD_CPSMEN;
+ while (((sta = sdcp->sdmmc->STA) & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL)) == 0)
+ ;
+ sdcp->sdmmc->ICR = sta & (SDMMC_STA_CMDREND | SDMMC_STA_CTIMEOUT |
+ SDMMC_STA_CCRCFAIL);
+ if ((sta & (SDMMC_STA_ERROR_MASK)) != 0) {
+ sdc_lld_collect_errors(sdcp, sta);
+ return HAL_FAILED;
+ }
+ /* Save bytes in reverse order because MSB in response comes first.*/
+ *resp++ = sdcp->sdmmc->RESP4;
+ *resp++ = sdcp->sdmmc->RESP3;
+ *resp++ = sdcp->sdmmc->RESP2;
+ *resp = sdcp->sdmmc->RESP1;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Reads special registers using data bus.
+ * @details Needs only during card detection procedure.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[out] buf pointer to the read buffer
+ * @param[in] bytes number of bytes to read
+ * @param[in] cmd card command
+ * @param[in] arg argument for command
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes,
+ uint8_t cmd, uint32_t arg) {
+ uint32_t resp[1];
+
+ if (sdc_lld_prepare_read_bytes(sdcp, buf, bytes))
+ goto error;
+
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | cmd, arg, resp) ||
+ MMCSD_R1_ERROR(resp[0]))
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, 1, resp))
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, 1, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] blocks number of blocks to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks) {
+ uint32_t resp[1];
+
+ osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE);
+
+ sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_READ_TIMEOUT;
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Setting up data transfer.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE |
+ SDMMC_MASK_DTIMEOUTIE |
+ SDMMC_MASK_RXOVERRIE |
+ SDMMC_MASK_DATAENDIE;
+ sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE;
+
+ /* Transfer modes.*/
+ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DTDIR |
+ SDMMC_DCTRL_DBLOCKSIZE_3 |
+ SDMMC_DCTRL_DBLOCKSIZE_0;
+
+ /* Prepares IDMA.*/
+ sdcp->sdmmc->IDMABASE0 = (uint32_t)buf;
+ sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN;
+
+ if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true)
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, blocks, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] n number of blocks to write
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks) {
+ uint32_t resp[1];
+
+ osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE);
+
+ sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_WRITE_TIMEOUT;
+
+ /* Checks for errors and waits for the card to be ready for writing.*/
+ if (_sdc_wait_for_transfer_state(sdcp))
+ return HAL_FAILED;
+
+ /* Setting up data transfer.*/
+ sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
+ sdcp->sdmmc->MASK = SDMMC_MASK_DCRCFAILIE |
+ SDMMC_MASK_DTIMEOUTIE |
+ SDMMC_MASK_TXUNDERRIE |
+ SDMMC_MASK_DATAENDIE;
+ sdcp->sdmmc->DLEN = blocks * MMCSD_BLOCK_SIZE;
+
+ /* Transfer modes.*/
+ sdcp->sdmmc->DCTRL = SDMMC_DCTRL_DBLOCKSIZE_3 |
+ SDMMC_DCTRL_DBLOCKSIZE_0;
+
+ /* Prepares IDMA.*/
+ sdcp->sdmmc->IDMABASE0 = (uint32_t)buf;
+ sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN;
+
+ if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == true)
+ goto error;
+
+ if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
+ goto error;
+
+ return HAL_SUCCESS;
+
+error:
+ sdc_lld_error_cleanup(sdcp, blocks, resp);
+ return HAL_FAILED;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] blocks number of blocks to read
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks) {
+
+#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < blocks; i++) {
+ if (sdc_lld_read_aligned(sdcp, startblk, sdcp->buf, 1))
+ return HAL_FAILED;
+ memcpy(buf, sdcp->buf, MMCSD_BLOCK_SIZE);
+ buf += MMCSD_BLOCK_SIZE;
+ startblk++;
+ }
+ return HAL_SUCCESS;
+ }
+#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer");
+#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ return sdc_lld_read_aligned(sdcp, startblk, buf, blocks);
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] blocks number of blocks to write
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS operation succeeded.
+ * @retval HAL_FAILED operation failed.
+ *
+ * @notapi
+ */
+bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks) {
+
+#if STM32_SDC_SDMMC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < blocks; i++) {
+ memcpy(sdcp->buf, buf, MMCSD_BLOCK_SIZE);
+ buf += MMCSD_BLOCK_SIZE;
+ if (sdc_lld_write_aligned(sdcp, startblk, sdcp->buf, 1))
+ return HAL_FAILED;
+ startblk++;
+ }
+ return HAL_SUCCESS;
+ }
+#else /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ osalDbgAssert((((unsigned)buf & 3) == 0), "unaligned buffer");
+#endif /* !STM32_SDC_SDIO_UNALIGNED_SUPPORT */
+ return sdc_lld_write_aligned(sdcp, startblk, buf, blocks);
+}
+
+/**
+ * @brief Waits for card idle condition.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @return The operation status.
+ * @retval HAL_SUCCESS the operation succeeded.
+ * @retval HAL_FAILED the operation failed.
+ *
+ * @api
+ */
+bool sdc_lld_sync(SDCDriver *sdcp) {
+
+ /* CHTODO: Implement.*/
+ (void)sdcp;
+ return HAL_SUCCESS;
+}
+
+/**
+ * @brief Shared service routine.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ */
+void sdc_lld_serve_interrupt(SDCDriver *sdcp) {
+
+ /* Disables the source but the status flags are not reset because the
+ read/write functions needs to check them.*/
+ sdcp->sdmmc->MASK = 0;
+
+ osalSysLockFromISR();
+ osalThreadResumeI(&sdcp->thread, MSG_OK);
+ osalSysUnlockFromISR();
+}
+
+#endif /* HAL_USE_SDC */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h new file mode 100644 index 0000000..334bf7a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h @@ -0,0 +1,301 @@ +/*
+ 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 SDMMCv2/hal_sdc_lld.h
+ * @brief STM32 SDC subsystem low level driver header.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#ifndef HAL_SDC_LLD_H
+#define HAL_SDC_LLD_H
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SDMMC1 driver enable switch.
+ * @details If set to @p TRUE the support for SDMMC1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SDC_USE_SDMMC1) || defined(__DOXYGEN__)
+#define STM32_SDC_USE_SDMMC1 FALSE
+#endif
+
+/**
+ * @brief SDMMC2 driver enable switch.
+ * @details If set to @p TRUE the support for SDMMC2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SDC_USE_SDMMC2) || defined(__DOXYGEN__)
+#define STM32_SDC_USE_SDMMC2 FALSE
+#endif
+
+/**
+ * @brief Support for unaligned transfers.
+ * @note Unaligned transfers are much slower.
+ */
+#if !defined(STM32_SDC_SDMMC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE
+#endif
+
+/**
+ * @brief Write timeout in card clock cycles.
+ */
+#if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000
+#endif
+
+/**
+ * @brief Read timeout in card clock cycles.
+ */
+#if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_READ_TIMEOUT 1000000
+#endif
+
+/**
+ * @brief Card clock activation delay in milliseconds.
+ */
+#if !defined(STM32_SDC_SDMMC_CLOCK_DELAY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_CLOCK_DELAY 10
+#endif
+
+/**
+ * @brief Card clock power saving enable.
+ */
+#if !defined(STM32_SDC_SDMMC_PWRSAV) || defined(__DOXYGEN__)
+#define STM32_SDC_SDMMC_PWRSAV TRUE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* Registry checks.*/
+#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_HANDLER)) || \
+ (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_HANDLER))
+#error "STM32_SDMMCx_HANDLER not defined in registry"
+#endif
+
+#if (STM32_SDC_USE_SDMMC1 && !defined(STM32_SDMMC1_NUMBER)) || \
+ (STM32_SDC_USE_SDMMC2 && !defined(STM32_SDMMC2_NUMBER))
+#error "STM32_SDMMCx_NUMBER not defined in registry"
+#endif
+
+/* Units checks.*/
+#if STM32_SDC_USE_SDMMC1 && !STM32_HAS_SDMMC1
+#error "SDMMC1 not present in the selected device"
+#endif
+
+#if STM32_SDC_USE_SDMMC2 && !STM32_HAS_SDMMC2
+#error "SDMMC2 not present in the selected device"
+#endif
+
+#if !STM32_SDC_USE_SDMMC1 && !STM32_SDC_USE_SDMMC2
+#error "SDC driver activated but no SDMMC peripheral assigned"
+#endif
+
+/* Clock related tests.*/
+#if STM32_HAS_SDMMC1 && !defined(STM32_SDMMC1CLK)
+#error "STM32_SDMMC1CLK not defined"
+#endif
+
+/* Clock related tests.*/
+#if STM32_HAS_SDMMC2 && !defined(STM32_SDMMC2CLK)
+#error "STM32_SDMMC2CLK not defined"
+#endif
+
+#if !defined(STM32_HCLK)
+#error "STM32_HCLK not defined"
+#endif
+
+#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK * 10 > STM32_HCLK * 7)
+#error "STM32_SDMMC1CLK must not exceed STM32_HCLK * 0.7"
+#endif
+
+#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK * 10 > STM32_HCLK * 7)
+#error "STM32_SDMMC2CLK must not exceed STM32_HCLK * 0.7"
+#endif
+
+#if !defined(STM32_SDMMC_MAXCLK)
+#define STM32_SDMMC_MAXCLK 50000000
+#endif
+
+#if STM32_HAS_SDMMC1 && (STM32_SDMMC1CLK > STM32_SDMMC_MAXCLK)
+#error "STM32_SDMMC1CLK must not exceed STM32_SDMMC_MAXCLK"
+#endif
+
+#if STM32_HAS_SDMMC2 && (STM32_SDMMC2CLK > STM32_SDMMC_MAXCLK)
+#error "STM32_SDMMC2CLK must not exceed STM32_SDMMC_MAXCLK"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of card flags.
+ */
+typedef uint32_t sdcmode_t;
+
+/**
+ * @brief SDC Driver condition flags type.
+ */
+typedef uint32_t sdcflags_t;
+
+/**
+ * @brief Type of a structure representing an SDC driver.
+ */
+typedef struct SDCDriver SDCDriver;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Bus width.
+ */
+ sdcbusmode_t bus_width;
+ /* End of the mandatory fields.*/
+} SDCConfig;
+
+/**
+ * @brief @p SDCDriver specific methods.
+ */
+#define _sdc_driver_methods \
+ _mmcsd_block_device_methods
+
+/**
+ * @extends MMCSDBlockDeviceVMT
+ *
+ * @brief @p SDCDriver virtual methods table.
+ */
+struct SDCDriverVMT {
+ _sdc_driver_methods
+};
+
+/**
+ * @brief Structure representing an SDC driver.
+ */
+struct SDCDriver {
+ /**
+ * @brief Virtual Methods Table.
+ */
+ const struct SDCDriverVMT *vmt;
+ _mmcsd_block_device_data
+ /**
+ * @brief Current configuration data.
+ */
+ const SDCConfig *config;
+ /**
+ * @brief Various flags regarding the mounted card.
+ */
+ sdcmode_t cardmode;
+ /**
+ * @brief Errors flags.
+ */
+ sdcflags_t errors;
+ /**
+ * @brief Card RCA.
+ */
+ uint32_t rca;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Thread waiting for I/O completion IRQ.
+ */
+ thread_reference_t thread;
+ /**
+ * @brief Pointer to the SDMMC registers block.
+ * @note Needed for debugging aid.
+ */
+ SDMMC_TypeDef *sdmmc;
+ /**
+ * @brief Input clock frequency.
+ */
+ uint32_t clkfreq;
+ /**
+ * @brief Buffer for internal operations.
+ */
+ uint8_t buf[MMCSD_BLOCK_SIZE];
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SDC_USE_SDMMC1 && !defined(__DOXYGEN__)
+extern SDCDriver SDCD1;
+#endif
+
+#if STM32_SDC_USE_SDMMC2 && !defined(__DOXYGEN__)
+extern SDCDriver SDCD2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sdc_lld_init(void);
+ void sdc_lld_start(SDCDriver *sdcp);
+ void sdc_lld_stop(SDCDriver *sdcp);
+ void sdc_lld_start_clk(SDCDriver *sdcp);
+ void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk);
+ void sdc_lld_stop_clk(SDCDriver *sdcp);
+ void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode);
+ void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg);
+ bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp);
+ bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes,
+ uint8_t cmd, uint32_t argument);
+ bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t blocks);
+ bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t blocks);
+ bool sdc_lld_sync(SDCDriver *sdcp);
+ bool sdc_lld_is_card_inserted(SDCDriver *sdcp);
+ bool sdc_lld_is_write_protected(SDCDriver *sdcp);
+ void sdc_lld_serve_interrupt(SDCDriver *sdcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SDC */
+
+#endif /* HAL_SDC_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc new file mode 100644 index 0000000..ae7b38e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc1.inc @@ -0,0 +1,110 @@ +/* + 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 SDMMCv2/stm32_sdmmc1.inc + * @brief Shared SDMMC1 handler. + * + * @addtogroup STM32_SDMMC1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_SDMMC1) +#error "STM32_HAS_SDMMC1 not defined in registry" +#endif + +#if STM32_HAS_SDMMC1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_SDMMC1_PRIORITY) +#error "STM32_IRQ_SDMMC1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_SDMMC1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_SDMMC1_PRIORITY" +#endif + +#endif /* STM32_HAS_SDMMC1 */ + +/* Other checks.*/ +#if (HAL_USE_SDC && STM32_SDC_USE_SDMMC1) +#define STM32_SDMMC1_IS_USED TRUE +#else +#define STM32_SDMMC1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void sdmmc1_irq_init(void) { +#if STM32_SDMMC1_IS_USED + nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_IRQ_SDMMC1_PRIORITY); +#endif +} + +static inline void sdmmc1_irq_deinit(void) { +#if STM32_SDMMC1_IS_USED + nvicDisableVector(STM32_SDMMC1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SDMMC1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief SDMMC1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SDMMC1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SDC +#if STM32_SDC_USE_SDMMC1 + sdc_lld_serve_interrupt(&SDCD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc new file mode 100644 index 0000000..75c614c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SDMMCv2/stm32_sdmmc2.inc @@ -0,0 +1,110 @@ +/* + 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 SDMMCv2/stm32_sdmmc2.inc + * @brief Shared SDMMC2 handler. + * + * @addtogroup STM32_SDMMC2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_SDMMC2) +#error "STM32_HAS_SDMMC2 not defined in registry" +#endif + +#if STM32_HAS_SDMMC2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_SDMMC2_PRIORITY) +#error "STM32_IRQ_SDMMC2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_SDMMC2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_SDMMC2_PRIORITY" +#endif + +#endif /* STM32_HAS_SDMMC2 */ + +/* Other checks.*/ +#if (HAL_USE_SDC && STM32_SDC_USE_SDMMC2) +#define STM32_SDMMC2_IS_USED TRUE +#else +#define STM32_SDMMC2_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void sdmmc2_irq_init(void) { +#if STM32_SDMMC2_IS_USED + nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_IRQ_SDMMC2_PRIORITY); +#endif +} + +static inline void sdmmc2_irq_deinit(void) { +#if STM32_SDMMC2_IS_USED + nvicDisableVector(STM32_SDMMC2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_SDMMC2_IS_USED|| defined(__DOXYGEN__) +/** + * @brief SDMMC2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SDMMC2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SDC +#if STM32_SDC_USE_SDMMC2 + sdc_lld_serve_interrupt(&SDCD2); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk new file mode 100644 index 0000000..1af9692 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_I2S TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c
+endif
+ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c new file mode 100644 index 0000000..235d2b8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.c @@ -0,0 +1,584 @@ +/*
+ 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 SPIv1/hal_i2s_lld.c
+ * @brief STM32 I2S subsystem low level driver source.
+ *
+ * @addtogroup I2S
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_I2S || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define I2S1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_RX_DMA_STREAM, \
+ STM32_SPI1_RX_DMA_CHN)
+
+#define I2S1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_TX_DMA_STREAM, \
+ STM32_SPI1_TX_DMA_CHN)
+
+#define I2S2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_RX_DMA_STREAM, \
+ STM32_SPI2_RX_DMA_CHN)
+
+#define I2S2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_TX_DMA_STREAM, \
+ STM32_SPI2_TX_DMA_CHN)
+
+#define I2S3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_RX_DMA_STREAM, \
+ STM32_SPI3_RX_DMA_CHN)
+
+#define I2S3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_TX_DMA_STREAM, \
+ STM32_SPI3_TX_DMA_CHN)
+
+/*
+ * Static I2S settings for I2S1.
+ */
+#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE)
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG 0
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_0
+#endif
+#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_1
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \
+ SPI_I2SCFGR_I2SCFG_0)
+#endif
+#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */
+
+/*
+ * Static I2S settings for I2S2.
+ */
+#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE)
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG 0
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_0
+#endif
+#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_1
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \
+ SPI_I2SCFGR_I2SCFG_0)
+#endif
+#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */
+
+/*
+ * Static I2S settings for I2S3.
+ */
+#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE)
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG 0
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_0
+#endif
+#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_1
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \
+ SPI_I2SCFGR_I2SCFG_0)
+#endif
+#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief I2S1 driver identifier.*/
+#if STM32_I2S_USE_SPI1 || defined(__DOXYGEN__)
+I2SDriver I2SD1;
+#endif
+
+/** @brief I2S2 driver identifier.*/
+#if STM32_I2S_USE_SPI2 || defined(__DOXYGEN__)
+I2SDriver I2SD2;
+#endif
+
+/** @brief I2S3 driver identifier.*/
+#if STM32_I2S_USE_SPI3 || defined(__DOXYGEN__)
+I2SDriver I2SD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) || \
+ STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) || \
+ STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared end-of-rx service routine.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void i2s_lld_serve_rx_interrupt(I2SDriver *i2sp, uint32_t flags) {
+
+ (void)i2sp;
+
+ /* DMA errors handling.*/
+#if defined(STM32_I2S_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_I2S_DMA_ERROR_HOOK(i2sp);
+ }
+#endif
+
+ /* Callbacks handling, note it is portable code defined in the high
+ level driver.*/
+ if ((flags & STM32_DMA_ISR_TCIF) != 0) {
+ /* Transfer complete processing.*/
+ _i2s_isr_full_code(i2sp);
+ }
+ else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
+ /* Half transfer processing.*/
+ _i2s_isr_half_code(i2sp);
+ }
+}
+#endif
+
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) || \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) || \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared end-of-tx service routine.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void i2s_lld_serve_tx_interrupt(I2SDriver *i2sp, uint32_t flags) {
+
+ (void)i2sp;
+
+ /* DMA errors handling.*/
+#if defined(STM32_I2S_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_I2S_DMA_ERROR_HOOK(i2sp);
+ }
+#endif
+
+ /* Callbacks handling, note it is portable code defined in the high
+ level driver.*/
+ if ((flags & STM32_DMA_ISR_TCIF) != 0) {
+ /* Transfer complete processing.*/
+ _i2s_isr_full_code(i2sp);
+ }
+ else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
+ /* Half transfer processing.*/
+ _i2s_isr_half_code(i2sp);
+ }
+}
+#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level I2S driver initialization.
+ *
+ * @notapi
+ */
+void i2s_lld_init(void) {
+
+#if STM32_I2S_USE_SPI1
+ i2sObjectInit(&I2SD1);
+ I2SD1.spi = SPI1;
+ I2SD1.cfg = STM32_I2S1_CFGR_CFG;
+ I2SD1.dmarx = NULL;
+ I2SD1.dmatx = NULL;
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+ I2SD1.rxdmamode = STM32_DMA_CR_CHSEL(I2S1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD1.rxdmamode = 0;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+ I2SD1.txdmamode = STM32_DMA_CR_CHSEL(I2S1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD1.txdmamode = 0;
+#endif
+#endif
+
+#if STM32_I2S_USE_SPI2
+ i2sObjectInit(&I2SD2);
+ I2SD2.spi = SPI2;
+ I2SD2.cfg = STM32_I2S2_CFGR_CFG;
+ I2SD2.dmarx = NULL;
+ I2SD2.dmatx = NULL;
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+ I2SD2.rxdmamode = STM32_DMA_CR_CHSEL(I2S2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD2.rxdmamode = 0;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+ I2SD2.txdmamode = STM32_DMA_CR_CHSEL(I2S2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD2.txdmamode = 0;
+#endif
+#endif
+
+#if STM32_I2S_USE_SPI3
+ i2sObjectInit(&I2SD3);
+ I2SD3.spi = SPI3;
+ I2SD3.cfg = STM32_I2S3_CFGR_CFG;
+ I2SD3.dmarx = NULL;
+ I2SD3.dmatx = NULL;
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+ I2SD3.rxdmamode = STM32_DMA_CR_CHSEL(I2S3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD3.rxdmamode = 0;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+ I2SD3.txdmamode = STM32_DMA_CR_CHSEL(I2S3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD3.txdmamode = 0;
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the I2S peripheral.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_start(I2SDriver *i2sp) {
+
+ /* If in stopped state then enables the SPI and DMA clocks.*/
+ if (i2sp->state == I2S_STOP) {
+
+#if STM32_I2S_USE_SPI1
+ if (&I2SD1 == i2sp) {
+
+ /* Enabling I2S unit clock.*/
+ rccEnableSPI1(true);
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+ i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI1_RX_DMA_STREAM,
+ STM32_I2S_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_RXDMAEN;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+ i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI1_TX_DMA_STREAM,
+ STM32_I2S_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_TXDMAEN;
+#endif
+ }
+#endif
+
+#if STM32_I2S_USE_SPI2
+ if (&I2SD2 == i2sp) {
+
+ /* Enabling I2S unit clock.*/
+ rccEnableSPI2(true);
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+ i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI2_RX_DMA_STREAM,
+ STM32_I2S_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_RXDMAEN;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+ i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI2_TX_DMA_STREAM,
+ STM32_I2S_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_TXDMAEN;
+#endif
+ }
+#endif
+
+#if STM32_I2S_USE_SPI3
+ if (&I2SD3 == i2sp) {
+
+ /* Enabling I2S unit clock.*/
+ rccEnableSPI3(true);
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+ i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI3_RX_DMA_STREAM,
+ STM32_I2S_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_RXDMAEN;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+ i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI3_TX_DMA_STREAM,
+ STM32_I2S_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_TXDMAEN;
+#endif
+ }
+#endif
+ }
+
+ /* I2S (re)configuration.*/
+ i2sp->spi->I2SPR = i2sp->config->i2spr;
+ i2sp->spi->I2SCFGR = i2sp->config->i2scfgr | i2sp->cfg | SPI_I2SCFGR_I2SMOD;
+}
+
+/**
+ * @brief Deactivates the I2S peripheral.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_stop(I2SDriver *i2sp) {
+
+ /* If in ready state then disables the SPI clock.*/
+ if (i2sp->state == I2S_READY) {
+
+ /* SPI disable.*/
+ i2sp->spi->CR2 = 0;
+ if (NULL != i2sp->dmarx) {
+ dmaStreamFreeI(i2sp->dmarx);
+ i2sp->dmarx = NULL;
+ }
+ if (NULL != i2sp->dmatx) {
+ dmaStreamFreeI(i2sp->dmatx);
+ i2sp->dmatx = NULL;
+ }
+
+#if STM32_I2S_USE_SPI1
+ if (&I2SD1 == i2sp)
+ rccDisableSPI1();
+#endif
+
+#if STM32_I2S_USE_SPI2
+ if (&I2SD2 == i2sp)
+ rccDisableSPI2();
+#endif
+
+#if STM32_I2S_USE_SPI3
+ if (&I2SD3 == i2sp)
+ rccDisableSPI3();
+#endif
+ }
+}
+
+/**
+ * @brief Starts a I2S data exchange.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_start_exchange(I2SDriver *i2sp) {
+ size_t size = i2sp->config->size;
+
+ /* In 32 bit modes the DMA has to perform double operations because fetches
+ are always performed using 16 bit accesses.
+ DATLEN CHLEN SIZE
+ 00 (16) 0 (16) 16
+ 00 (16) 1 (32) 16
+ 01 (24) X 32
+ 10 (32) X 32
+ 11 (NA) X NA
+ */
+ if ((i2sp->config->i2scfgr & SPI_I2SCFGR_DATLEN) != 0)
+ size *= 2;
+
+ /* RX DMA setup.*/
+ if (NULL != i2sp->dmarx) {
+ dmaStreamSetMode(i2sp->dmarx, i2sp->rxdmamode);
+ dmaStreamSetPeripheral(i2sp->dmarx, &i2sp->spi->DR);
+ dmaStreamSetMemory0(i2sp->dmarx, i2sp->config->rx_buffer);
+ dmaStreamSetTransactionSize(i2sp->dmarx, size);
+ dmaStreamEnable(i2sp->dmarx);
+ }
+
+ /* TX DMA setup.*/
+ if (NULL != i2sp->dmatx) {
+ dmaStreamSetMode(i2sp->dmatx, i2sp->txdmamode);
+ dmaStreamSetPeripheral(i2sp->dmatx, &i2sp->spi->DR);
+ dmaStreamSetMemory0(i2sp->dmatx, i2sp->config->tx_buffer);
+ dmaStreamSetTransactionSize(i2sp->dmatx, size);
+ dmaStreamEnable(i2sp->dmatx);
+ }
+
+ /* Starting transfer.*/
+ i2sp->spi->I2SCFGR |= SPI_I2SCFGR_I2SE;
+}
+
+/**
+ * @brief Stops the ongoing data exchange.
+ * @details The ongoing data exchange, if any, is stopped, if the driver
+ * was not active the function does nothing.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_stop_exchange(I2SDriver *i2sp) {
+
+ /* Stop TX DMA, if enabled.*/
+ if (NULL != i2sp->dmatx) {
+ dmaStreamDisable(i2sp->dmatx);
+
+ /* From the RM: To switch off the I2S, by clearing I2SE, it is mandatory
+ to wait for TXE = 1 and BSY = 0.*/
+ while ((i2sp->spi->SR & (SPI_SR_TXE | SPI_SR_BSY)) != SPI_SR_TXE)
+ ;
+
+ /* Stop SPI/I2S peripheral.*/
+ i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
+ }
+
+ /* Stop RX DMA, if enabled then draining the RX DR.*/
+ if (NULL != i2sp->dmarx) {
+ dmaStreamDisable(i2sp->dmarx);
+
+ /* Waiting for some data to be present in RX DR.*/
+ while ((i2sp->spi->SR & SPI_SR_RXNE) != SPI_SR_RXNE)
+ ;
+
+ /* Stop SPI/I2S peripheral.*/
+ i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
+
+ /* Purging data in DR.*/
+ while ((i2sp->spi->SR & SPI_SR_RXNE) != 0)
+ (void) i2sp->spi->DR;
+ }
+}
+
+#endif /* HAL_USE_I2S */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h new file mode 100644 index 0000000..37b3f2a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_i2s_lld.h @@ -0,0 +1,371 @@ +/*
+ 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 SPIv1/hal_i2s_lld.h
+ * @brief STM32 I2S subsystem low level driver header.
+ *
+ * @addtogroup I2S
+ * @{
+ */
+
+#ifndef HAL_I2S_LLD_H
+#define HAL_I2S_LLD_H
+
+#if HAL_USE_I2S || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Static I2S modes
+ * @{
+ */
+#define STM32_I2S_MODE_SLAVE 0
+#define STM32_I2S_MODE_MASTER 1
+#define STM32_I2S_MODE_RX 2
+#define STM32_I2S_MODE_TX 4
+#define STM32_I2S_MODE_RXTX (STM32_I2S_MODE_RX | \
+ STM32_I2S_MODE_TX)
+/** @} */
+
+/**
+ * @name Mode checks
+ * @{
+ */
+#define STM32_I2S_IS_MASTER(mode) ((mode) & STM32_I2S_MODE_MASTER)
+#define STM32_I2S_RX_ENABLED(mode) ((mode) & STM32_I2S_MODE_RX)
+#define STM32_I2S_TX_ENABLED(mode) ((mode) & STM32_I2S_MODE_TX)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief I2S1 driver enable switch.
+ * @details If set to @p TRUE the support for I2S1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2S_USE_SPI1) || defined(__DOXYGEN__)
+#define STM32_I2S_USE_SPI1 FALSE
+#endif
+
+/**
+ * @brief I2S2 driver enable switch.
+ * @details If set to @p TRUE the support for I2S2 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2S_USE_SPI2) || defined(__DOXYGEN__)
+#define STM32_I2S_USE_SPI2 FALSE
+#endif
+
+/**
+ * @brief I2S3 driver enable switch.
+ * @details If set to @p TRUE the support for I2S3 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2S_USE_SPI3) || defined(__DOXYGEN__)
+#define STM32_I2S_USE_SPI3 FALSE
+#endif
+
+/**
+ * @brief I2S1 mode.
+ */
+#if !defined(STM32_I2S_SPI1_MODE) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI1_MODE (STM32_I2S_MODE_MASTER | \
+ STM32_I2S_MODE_RX)
+#endif
+
+/**
+ * @brief I2S2 mode.
+ */
+#if !defined(STM32_I2S_SPI2_MODE) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI2_MODE (STM32_I2S_MODE_MASTER | \
+ STM32_I2S_MODE_RX)
+#endif
+
+/**
+ * @brief I2S3 mode.
+ */
+#if !defined(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI3_MODE (STM32_I2S_MODE_MASTER | \
+ STM32_I2S_MODE_RX)
+#endif
+
+/**
+ * @brief I2S1 interrupt priority level setting.
+ */
+#if !defined(STM32_I2S_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2S2 interrupt priority level setting.
+ */
+#if !defined(STM32_I2S_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2S3 interrupt priority level setting.
+ */
+#if !defined(STM32_I2S_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2S1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_I2S_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2S2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_I2S_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2S3 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_I2S_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2S DMA error hook.
+ */
+#if !defined(STM32_I2S_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_I2S_USE_SPI1 && !STM32_SPI1_SUPPORTS_I2S
+#error "SPI1 does not support I2S mode"
+#endif
+
+#if STM32_I2S_USE_SPI2 && !STM32_SPI2_SUPPORTS_I2S
+#error "SPI2 does not support I2S mode"
+#endif
+
+#if STM32_I2S_USE_SPI3 && !STM32_SPI3_SUPPORTS_I2S
+#error "SPI3 does not support I2S mode"
+#endif
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) && \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+#error "I2S1 RX and TX mode not supported in this driver implementation"
+#endif
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) && \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+#error "I2S2 RX and TX mode not supported in this driver implementation"
+#endif
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) && \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+#error "I2S3 RX and TX mode not supported in this driver implementation"
+#endif
+
+#if STM32_I2S_USE_SPI1 && !STM32_HAS_SPI1
+#error "SPI1 not present in the selected device"
+#endif
+
+#if STM32_I2S_USE_SPI2 && !STM32_HAS_SPI2
+#error "SPI2 not present in the selected device"
+#endif
+
+#if STM32_I2S_USE_SPI3 && !STM32_HAS_SPI3
+#error "SPI3 not present in the selected device"
+#endif
+
+#if !STM32_I2S_USE_SPI1 && !STM32_I2S_USE_SPI2 && !STM32_I2S_USE_SPI3
+#error "I2S driver activated but no SPI peripheral assigned"
+#endif
+
+#if STM32_I2S_USE_SPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI1"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI2"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI3"
+#endif
+
+#if STM32_I2S_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI1"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI2"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI3"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_I2S_USE_SPI1 && (!defined(STM32_I2S_SPI1_RX_DMA_STREAM) || \
+ !defined(STM32_I2S_SPI1_TX_DMA_STREAM))
+#error "SPI1 DMA streams not defined"
+#endif
+
+#if STM32_I2S_USE_SPI2 && (!defined(STM32_I2S_SPI2_RX_DMA_STREAM) || \
+ !defined(STM32_I2S_SPI2_TX_DMA_STREAM))
+#error "SPI2 DMA streams not defined"
+#endif
+
+#if STM32_I2S_USE_SPI3 && (!defined(STM32_I2S_SPI3_RX_DMA_STREAM) || \
+ !defined(STM32_I2S_SPI3_TX_DMA_STREAM))
+#error "SPI3 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_I2S_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 RX"
+#endif
+
+#if STM32_I2S_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 TX"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 RX"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 TX"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 RX"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 TX"
+#endif
+#endif /* STM32_ADVANCED_DMA */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the I2S driver structure.
+ */
+#define i2s_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /* Calculated part of the I2SCFGR register.*/ \
+ uint16_t cfg; \
+ /* Receive DMA stream or @p NULL.*/ \
+ const stm32_dma_stream_t *dmarx; \
+ /* Transmit DMA stream or @p NULL.*/ \
+ const stm32_dma_stream_t *dmatx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+
+/**
+ * @brief Low level fields of the I2S configuration structure.
+ */
+#define i2s_lld_config_fields \
+ /* Configuration of the I2SCFGR register. \
+ NOTE: See the STM32 reference manual, this register is used for \
+ the I2S configuration, the following bits must not be \
+ specified because handled directly by the driver: \
+ - I2SMOD \
+ - I2SE \
+ - I2SCFG \
+ */ \
+ int16_t i2scfgr; \
+ /* Configuration of the I2SPR register. \
+ NOTE: See the STM32 reference manual, this register is used for \
+ the I2S clock setup.*/ \
+ int16_t i2spr
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_I2S_USE_SPI1 && !defined(__DOXYGEN__)
+extern I2SDriver I2SD1;
+#endif
+
+#if STM32_I2S_USE_SPI2 && !defined(__DOXYGEN__)
+extern I2SDriver I2SD2;
+#endif
+
+#if STM32_I2S_USE_SPI3 && !defined(__DOXYGEN__)
+extern I2SDriver I2SD3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void i2s_lld_init(void);
+ void i2s_lld_start(I2SDriver *i2sp);
+ void i2s_lld_stop(I2SDriver *i2sp);
+ void i2s_lld_start_exchange(I2SDriver *i2sp);
+ void i2s_lld_stop_exchange(I2SDriver *i2sp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_I2S */
+
+#endif /* HAL_I2S_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c new file mode 100644 index 0000000..459e6b9 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.c @@ -0,0 +1,679 @@ +/*
+ 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 SPIv1/hal_spi_lld.c
+ * @brief STM32 SPI subsystem low level driver source.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define SPI1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_RX_DMA_STREAM, \
+ STM32_SPI1_RX_DMA_CHN)
+
+#define SPI1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_TX_DMA_STREAM, \
+ STM32_SPI1_TX_DMA_CHN)
+
+#define SPI2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_RX_DMA_STREAM, \
+ STM32_SPI2_RX_DMA_CHN)
+
+#define SPI2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_TX_DMA_STREAM, \
+ STM32_SPI2_TX_DMA_CHN)
+
+#define SPI3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_RX_DMA_STREAM, \
+ STM32_SPI3_RX_DMA_CHN)
+
+#define SPI3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_TX_DMA_STREAM, \
+ STM32_SPI3_TX_DMA_CHN)
+
+#define SPI4_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_RX_DMA_STREAM, \
+ STM32_SPI4_RX_DMA_CHN)
+
+#define SPI4_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_TX_DMA_STREAM, \
+ STM32_SPI4_TX_DMA_CHN)
+
+#define SPI5_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_RX_DMA_STREAM, \
+ STM32_SPI5_RX_DMA_CHN)
+
+#define SPI5_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_TX_DMA_STREAM, \
+ STM32_SPI5_TX_DMA_CHN)
+
+#define SPI6_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_RX_DMA_STREAM, \
+ STM32_SPI6_RX_DMA_CHN)
+
+#define SPI6_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_TX_DMA_STREAM, \
+ STM32_SPI6_TX_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SPI1 driver identifier.*/
+#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
+SPIDriver SPID1;
+#endif
+
+/** @brief SPI2 driver identifier.*/
+#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
+SPIDriver SPID2;
+#endif
+
+/** @brief SPI3 driver identifier.*/
+#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
+SPIDriver SPID3;
+#endif
+
+/** @brief SPI4 driver identifier.*/
+#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__)
+SPIDriver SPID4;
+#endif
+
+/** @brief SPI5 driver identifier.*/
+#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__)
+SPIDriver SPID5;
+#endif
+
+/** @brief SPI6 driver identifier.*/
+#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__)
+SPIDriver SPID6;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const uint16_t dummytx = 0xFFFFU;
+static uint16_t dummyrx;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Shared end-of-rx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (spip->config->circular) {
+ if ((flags & STM32_DMA_ISR_HTIF) != 0U) {
+ /* Half buffer interrupt.*/
+ _spi_isr_half_code(spip);
+ }
+ if ((flags & STM32_DMA_ISR_TCIF) != 0U) {
+ /* End buffer interrupt.*/
+ _spi_isr_full_code(spip);
+ }
+ }
+ else {
+ /* Stopping DMAs.*/
+ dmaStreamDisable(spip->dmatx);
+ dmaStreamDisable(spip->dmarx);
+
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+ }
+}
+
+/**
+ * @brief Shared end-of-tx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ (void)spip;
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)spip;
+ (void)flags;
+#endif
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SPI driver initialization.
+ *
+ * @notapi
+ */
+void spi_lld_init(void) {
+
+#if STM32_SPI_USE_SPI1
+ spiObjectInit(&SPID1);
+ SPID1.spi = SPI1;
+ SPID1.dmarx = NULL;
+ SPID1.dmatx = NULL;
+ SPID1.rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID1.txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI2
+ spiObjectInit(&SPID2);
+ SPID2.spi = SPI2;
+ SPID2.dmarx = NULL;
+ SPID2.dmatx = NULL;
+ SPID2.rxdmamode = STM32_DMA_CR_CHSEL(SPI2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID2.txdmamode = STM32_DMA_CR_CHSEL(SPI2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI3
+ spiObjectInit(&SPID3);
+ SPID3.spi = SPI3;
+ SPID3.dmarx = NULL;
+ SPID3.dmatx = NULL;
+ SPID3.rxdmamode = STM32_DMA_CR_CHSEL(SPI3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID3.txdmamode = STM32_DMA_CR_CHSEL(SPI3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI4
+ spiObjectInit(&SPID4);
+ SPID4.spi = SPI4;
+ SPID4.dmarx = NULL;
+ SPID4.dmatx = NULL;
+ SPID4.rxdmamode = STM32_DMA_CR_CHSEL(SPI4_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID4.txdmamode = STM32_DMA_CR_CHSEL(SPI4_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI5
+ spiObjectInit(&SPID5);
+ SPID5.spi = SPI5;
+ SPID5.dmarx = NULL;
+ SPID5.dmatx = NULL;
+ SPID5.rxdmamode = STM32_DMA_CR_CHSEL(SPI5_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID5.txdmamode = STM32_DMA_CR_CHSEL(SPI5_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI6
+ spiObjectInit(&SPID6);
+ SPID6.spi = SPI6;
+ SPID6.dmarx = NULL;
+ SPID6.dmatx = NULL;
+ SPID6.rxdmamode = STM32_DMA_CR_CHSEL(SPI6_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID6.txdmamode = STM32_DMA_CR_CHSEL(SPI6_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+}
+
+/**
+ * @brief Configures and activates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_start(SPIDriver *spip) {
+
+ /* If in stopped state then enables the SPI and DMA clocks.*/
+ if (spip->state == SPI_STOP) {
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI1_RX_DMA_STREAM,
+ STM32_SPI_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI1_TX_DMA_STREAM,
+ STM32_SPI_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI1(true);
+ }
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI2_RX_DMA_STREAM,
+ STM32_SPI_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI2_TX_DMA_STREAM,
+ STM32_SPI_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI2(true);
+ }
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI3_RX_DMA_STREAM,
+ STM32_SPI_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI3_TX_DMA_STREAM,
+ STM32_SPI_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI3(true);
+ }
+#endif
+#if STM32_SPI_USE_SPI4
+ if (&SPID4 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI4_RX_DMA_STREAM,
+ STM32_SPI_SPI4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI4_TX_DMA_STREAM,
+ STM32_SPI_SPI4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI4(true);
+ }
+#endif
+#if STM32_SPI_USE_SPI5
+ if (&SPID5 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI5_RX_DMA_STREAM,
+ STM32_SPI_SPI5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI5_TX_DMA_STREAM,
+ STM32_SPI_SPI5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI5(true);
+ }
+#endif
+#if STM32_SPI_USE_SPI6
+ if (&SPID6 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI6_RX_DMA_STREAM,
+ STM32_SPI_SPI6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI6_TX_DMA_STREAM,
+ STM32_SPI_SPI6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI6(true);
+ }
+#endif
+
+ /* DMA setup.*/
+ dmaStreamSetPeripheral(spip->dmarx, &spip->spi->DR);
+ dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR);
+ }
+
+ /* Configuration-specific DMA setup.*/
+ if ((spip->config->cr1 & SPI_CR1_DFF) == 0) {
+ /* Frame width is 8 bits or smaller.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ }
+ else {
+ /* Frame width is larger than 8 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ }
+
+ if (spip->config->circular) {
+ spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ }
+ else {
+ spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ }
+
+ /* SPI setup and enable.*/
+ spip->spi->CR1 &= ~SPI_CR1_SPE;
+ spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM |
+ SPI_CR1_SSI;
+ spip->spi->CR2 = spip->config->cr2 | SPI_CR2_SSOE | SPI_CR2_RXDMAEN |
+ SPI_CR2_TXDMAEN;
+ spip->spi->CR1 |= SPI_CR1_SPE;
+}
+
+/**
+ * @brief Deactivates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_stop(SPIDriver *spip) {
+
+ /* If in ready state then disables the SPI clock.*/
+ if (spip->state == SPI_READY) {
+
+ /* SPI disable.*/
+ spip->spi->CR1 &= ~SPI_CR1_SPE;
+ spip->spi->CR1 = 0;
+ spip->spi->CR2 = 0;
+ dmaStreamFreeI(spip->dmarx);
+ dmaStreamFreeI(spip->dmatx);
+ spip->dmarx = NULL;
+ spip->dmatx = NULL;
+
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip)
+ rccDisableSPI1();
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip)
+ rccDisableSPI2();
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip)
+ rccDisableSPI3();
+#endif
+#if STM32_SPI_USE_SPI4
+ if (&SPID4 == spip)
+ rccDisableSPI4();
+#endif
+#if STM32_SPI_USE_SPI5
+ if (&SPID5 == spip)
+ rccDisableSPI5();
+#endif
+#if STM32_SPI_USE_SPI6
+ if (&SPID6 == spip)
+ rccDisableSPI6();
+#endif
+ }
+}
+
+#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
+/**
+ * @brief Asserts the slave select signal and prepares for transfers.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_select(SPIDriver *spip) {
+
+ /* No implementation on STM32.*/
+}
+
+/**
+ * @brief Deasserts the slave select signal.
+ * @details The previously selected peripheral is unselected.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_unselect(SPIDriver *spip) {
+
+ /* No implementation on STM32.*/
+}
+#endif
+
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This asynchronous function starts the transmission of a series of
+ * idle words on the SPI bus and ignores the received data.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be ignored
+ *
+ * @notapi
+ */
+void spi_lld_ignore(SPIDriver *spip, size_t n) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, &dummyrx);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
+
+ dmaStreamSetMemory0(spip->dmatx, &dummytx);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode| STM32_DMA_CR_MINC);
+
+ dmaStreamSetMemory0(spip->dmatx, txbuf);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, &dummyrx);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
+
+ dmaStreamSetMemory0(spip->dmatx, txbuf);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamSetMemory0(spip->dmatx, &dummytx);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Aborts the ongoing SPI operation, if any.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_abort(SPIDriver *spip) {
+
+ /* Stopping DMAs.*/
+ dmaStreamDisable(spip->dmatx);
+ dmaStreamDisable(spip->dmarx);
+}
+#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */
+
+/**
+ * @brief Exchanges one frame using a polled wait.
+ * @details This synchronous function exchanges one frame using a polled
+ * synchronization method. This function is useful when exchanging
+ * small amount of data on high speed channels, usually in this
+ * situation is much more efficient just wait for completion using
+ * polling than suspending the thread waiting for an interrupt.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] frame the data frame to send over the SPI bus
+ * @return The received data frame from the SPI bus.
+ */
+uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
+
+ spip->spi->DR = frame;
+ while ((spip->spi->SR & SPI_SR_RXNE) == 0)
+ ;
+ return spip->spi->DR;
+}
+
+#endif /* HAL_USE_SPI */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h new file mode 100644 index 0000000..09a6eec --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv1/hal_spi_lld.h @@ -0,0 +1,495 @@ +/*
+ 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 SPIv1/hal_spi_lld.h
+ * @brief STM32 SPI subsystem low level driver header.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef HAL_SPI_LLD_H
+#define HAL_SPI_LLD_H
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Circular mode support flag.
+ */
+#define SPI_SUPPORTS_CIRCULAR TRUE
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SPI1 driver enable switch.
+ * @details If set to @p TRUE the support for SPI1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI1 FALSE
+#endif
+
+/**
+ * @brief SPI2 driver enable switch.
+ * @details If set to @p TRUE the support for SPI2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI2 FALSE
+#endif
+
+/**
+ * @brief SPI3 driver enable switch.
+ * @details If set to @p TRUE the support for SPI3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI3 FALSE
+#endif
+
+/**
+ * @brief SPI4 driver enable switch.
+ * @details If set to @p TRUE the support for SPI4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI4 FALSE
+#endif
+
+/**
+ * @brief SPI5 driver enable switch.
+ * @details If set to @p TRUE the support for SPI5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI5 FALSE
+#endif
+
+/**
+ * @brief SPI6 driver enable switch.
+ * @details If set to @p TRUE the support for SPI6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI6 FALSE
+#endif
+
+/**
+ * @brief SPI1 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI2 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI3 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI4 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI4_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI5 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI5_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI6 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI6_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI4_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI5 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI5_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI6 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI6_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI DMA error hook.
+ */
+#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1
+#error "SPI1 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2
+#error "SPI2 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3
+#error "SPI3 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4
+#error "SPI4 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5
+#error "SPI5 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6
+#error "SPI6 not present in the selected device"
+#endif
+
+#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \
+ !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6
+#error "SPI driver activated but no SPI peripheral assigned"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI1"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI2"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI3"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI4"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI5"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI6"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI1"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI2"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI3"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI4"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI5"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI6"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI1_TX_DMA_STREAM))
+#error "SPI1 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI2_TX_DMA_STREAM))
+#error "SPI2 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI3_TX_DMA_STREAM))
+#error "SPI3 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI4_TX_DMA_STREAM))
+#error "SPI4 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI5_TX_DMA_STREAM))
+#error "SPI5 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI6_TX_DMA_STREAM))
+#error "SPI6 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 RX"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 TX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 RX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 TX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 RX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 TX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_RX_DMA_STREAM, STM32_SPI4_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI4 RX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_TX_DMA_STREAM, STM32_SPI4_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI4 TX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_RX_DMA_STREAM, STM32_SPI5_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI5 RX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_TX_DMA_STREAM, STM32_SPI5_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI5 TX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_RX_DMA_STREAM, STM32_SPI6_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI6 RX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_TX_DMA_STREAM, STM32_SPI6_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI6 TX"
+#endif
+#endif /* STM32_ADVANCED_DMA */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD
+#error "SPI_SELECT_MODE_LLD not supported by this driver"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the SPI driver structure.
+ */
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /* Receive DMA stream.*/ \
+ const stm32_dma_stream_t *dmarx; \
+ /* Transmit DMA stream.*/ \
+ const stm32_dma_stream_t *dmatx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+
+/**
+ * @brief Low level fields of the SPI configuration structure.
+ */
+#define spi_lld_config_fields \
+ /* SPI CR1 register initialization data.*/ \
+ uint16_t cr1; \
+ /* SPI CR2 register initialization data.*/ \
+ uint16_t cr2
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__)
+extern SPIDriver SPID1;
+#endif
+
+#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__)
+extern SPIDriver SPID2;
+#endif
+
+#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__)
+extern SPIDriver SPID3;
+#endif
+
+#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__)
+extern SPIDriver SPID4;
+#endif
+
+#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__)
+extern SPIDriver SPID5;
+#endif
+
+#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__)
+extern SPIDriver SPID6;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void spi_lld_init(void);
+ void spi_lld_start(SPIDriver *spip);
+ void spi_lld_stop(SPIDriver *spip);
+#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
+ void spi_lld_select(SPIDriver *spip);
+ void spi_lld_unselect(SPIDriver *spip);
+#endif
+ void spi_lld_ignore(SPIDriver *spip, size_t n);
+ void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf);
+ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
+ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
+ void spi_lld_abort(SPIDriver *spip);
+#endif
+ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SPI */
+
+#endif /* HAL_SPI_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk new file mode 100644 index 0000000..2e1bae4 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_I2S TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c
+endif
+ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c new file mode 100644 index 0000000..aa437da --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.c @@ -0,0 +1,572 @@ +/*
+ 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 SPIv2/hal_i2s_lld.c
+ * @brief STM32 I2S subsystem low level driver source.
+ *
+ * @addtogroup I2S
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_I2S || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define I2S1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_RX_DMA_STREAM, \
+ STM32_SPI1_RX_DMA_CHN)
+
+#define I2S1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI1_TX_DMA_STREAM, \
+ STM32_SPI1_TX_DMA_CHN)
+
+#define I2S2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_RX_DMA_STREAM, \
+ STM32_SPI2_RX_DMA_CHN)
+
+#define I2S2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI2_TX_DMA_STREAM, \
+ STM32_SPI2_TX_DMA_CHN)
+
+#define I2S3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_RX_DMA_STREAM, \
+ STM32_SPI3_RX_DMA_CHN)
+
+#define I2S3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2S_SPI3_TX_DMA_STREAM, \
+ STM32_SPI3_TX_DMA_CHN)
+
+/*
+ * Static I2S settings for I2S1.
+ */
+#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE)
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG 0
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_0
+#endif
+#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG SPI_I2SCFGR_I2SCFG_1
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+#define STM32_I2S1_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \
+ SPI_I2SCFGR_I2SCFG_0)
+#endif
+#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI1_MODE) */
+
+/*
+ * Static I2S settings for I2S2.
+ */
+#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE)
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG 0
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_0
+#endif
+#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG SPI_I2SCFGR_I2SCFG_1
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+#define STM32_I2S2_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \
+ SPI_I2SCFGR_I2SCFG_0)
+#endif
+#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI2_MODE) */
+
+/*
+ * Static I2S settings for I2S3.
+ */
+#if !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE)
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG 0
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_0
+#endif
+#else /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG SPI_I2SCFGR_I2SCFG_1
+#endif
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+#define STM32_I2S3_CFGR_CFG (SPI_I2SCFGR_I2SCFG_1 | \
+ SPI_I2SCFGR_I2SCFG_0)
+#endif
+#endif /* !STM32_I2S_IS_MASTER(STM32_I2S_SPI3_MODE) */
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief I2S1 driver identifier.*/
+#if STM32_I2S_USE_SPI1 || defined(__DOXYGEN__)
+I2SDriver I2SD1;
+#endif
+
+/** @brief I2S2 driver identifier.*/
+#if STM32_I2S_USE_SPI2 || defined(__DOXYGEN__)
+I2SDriver I2SD2;
+#endif
+
+/** @brief I2S3 driver identifier.*/
+#if STM32_I2S_USE_SPI3 || defined(__DOXYGEN__)
+I2SDriver I2SD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) || \
+ STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) || \
+ STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared end-of-rx service routine.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void i2s_lld_serve_rx_interrupt(I2SDriver *i2sp, uint32_t flags) {
+
+ (void)i2sp;
+
+ /* DMA errors handling.*/
+#if defined(STM32_I2S_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_I2S_DMA_ERROR_HOOK(i2sp);
+ }
+#endif
+
+ /* Callbacks handling, note it is portable code defined in the high
+ level driver.*/
+ if ((flags & STM32_DMA_ISR_TCIF) != 0) {
+ /* Transfer complete processing.*/
+ _i2s_isr_full_code(i2sp);
+ }
+ else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
+ /* Half transfer processing.*/
+ _i2s_isr_half_code(i2sp);
+ }
+}
+#endif
+
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE) || \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE) || \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared end-of-tx service routine.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void i2s_lld_serve_tx_interrupt(I2SDriver *i2sp, uint32_t flags) {
+
+ (void)i2sp;
+
+ /* DMA errors handling.*/
+#if defined(STM32_I2S_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_I2S_DMA_ERROR_HOOK(i2sp);
+ }
+#endif
+
+ /* Callbacks handling, note it is portable code defined in the high
+ level driver.*/
+ if ((flags & STM32_DMA_ISR_TCIF) != 0) {
+ /* Transfer complete processing.*/
+ _i2s_isr_full_code(i2sp);
+ }
+ else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
+ /* Half transfer processing.*/
+ _i2s_isr_half_code(i2sp);
+ }
+}
+#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level I2S driver initialization.
+ *
+ * @notapi
+ */
+void i2s_lld_init(void) {
+
+#if STM32_I2S_USE_SPI1
+ i2sObjectInit(&I2SD1);
+ I2SD1.spi = SPI1;
+ I2SD1.cfg = STM32_I2S1_CFGR_CFG;
+ I2SD1.dmarx = NULL;
+ I2SD1.dmatx = NULL;
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+ I2SD1.rxdmamode = STM32_DMA_CR_CHSEL(I2S1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD1.rxdmamode = 0;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+ I2SD1.txdmamode = STM32_DMA_CR_CHSEL(I2S1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD1.txdmamode = 0;
+#endif
+#endif
+
+#if STM32_I2S_USE_SPI2
+ i2sObjectInit(&I2SD2);
+ I2SD2.spi = SPI2;
+ I2SD2.cfg = STM32_I2S2_CFGR_CFG;
+ I2SD2.dmarx = NULL;
+ I2SD2.dmatx = NULL;
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+ I2SD2.rxdmamode = STM32_DMA_CR_CHSEL(I2S2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD2.rxdmamode = 0;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+ I2SD2.txdmamode = STM32_DMA_CR_CHSEL(I2S2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD2.txdmamode = 0;
+#endif
+#endif
+
+#if STM32_I2S_USE_SPI3
+ i2sObjectInit(&I2SD3);
+ I2SD3.spi = SPI3;
+ I2SD3.cfg = STM32_I2S3_CFGR_CFG;
+ I2SD3.dmarx = NULL;
+ I2SD3.dmatx = NULL;
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+ I2SD3.rxdmamode = STM32_DMA_CR_CHSEL(I2S3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD3.rxdmamode = 0;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+ I2SD3.txdmamode = STM32_DMA_CR_CHSEL(I2S3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2S_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_HWORD |
+ STM32_DMA_CR_MSIZE_HWORD |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_CIRC |
+ STM32_DMA_CR_HTIE |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#else
+ I2SD3.txdmamode = 0;
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the I2S peripheral.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_start(I2SDriver *i2sp) {
+
+ /* If in stopped state then enables the SPI and DMA clocks.*/
+ if (i2sp->state == I2S_STOP) {
+
+#if STM32_I2S_USE_SPI1
+ if (&I2SD1 == i2sp) {
+
+ /* Enabling I2S unit clock.*/
+ rccEnableSPI1(true);
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE)
+ i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI1_RX_DMA_STREAM,
+ STM32_I2S_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_RXDMAEN;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+ i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI1_TX_DMA_STREAM,
+ STM32_I2S_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_TXDMAEN;
+#endif
+ }
+#endif
+
+#if STM32_I2S_USE_SPI2
+ if (&I2SD2 == i2sp) {
+
+ /* Enabling I2S unit clock.*/
+ rccEnableSPI2(true);
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE)
+ i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI2_RX_DMA_STREAM,
+ STM32_I2S_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_RXDMAEN;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+ i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI2_TX_DMA_STREAM,
+ STM32_I2S_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_TXDMAEN;
+#endif
+ }
+#endif
+
+#if STM32_I2S_USE_SPI3
+ if (&I2SD3 == i2sp) {
+
+ /* Enabling I2S unit clock.*/
+ rccEnableSPI3(true);
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE)
+ i2sp->dmarx = dmaStreamAllocI(STM32_I2S_SPI3_RX_DMA_STREAM,
+ STM32_I2S_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_rx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmarx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_RXDMAEN;
+#endif
+#if STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+ i2sp->dmatx = dmaStreamAllocI(STM32_I2S_SPI3_TX_DMA_STREAM,
+ STM32_I2S_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2s_lld_serve_tx_interrupt,
+ (void *)i2sp);
+ osalDbgAssert(i2sp->dmatx != NULL, "unable to allocate stream");
+
+ /* CRs settings are done here because those never changes until
+ the driver is stopped.*/
+ i2sp->spi->CR1 = 0;
+ i2sp->spi->CR2 = SPI_CR2_TXDMAEN;
+#endif
+ }
+#endif
+ }
+
+ /* I2S (re)configuration.*/
+ i2sp->spi->I2SPR = i2sp->config->i2spr;
+ i2sp->spi->I2SCFGR = i2sp->config->i2scfgr | i2sp->cfg | SPI_I2SCFGR_I2SMOD;
+}
+
+/**
+ * @brief Deactivates the I2S peripheral.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_stop(I2SDriver *i2sp) {
+
+ /* If in ready state then disables the SPI clock.*/
+ if (i2sp->state == I2S_READY) {
+
+ /* SPI disable.*/
+ i2sp->spi->CR2 = 0;
+ if (NULL != i2sp->dmarx) {
+ dmaStreamFreeI(i2sp->dmarx);
+ i2sp->dmarx = NULL;
+ }
+ if (NULL != i2sp->dmatx) {
+ dmaStreamFreeI(i2sp->dmatx);
+ i2sp->dmatx = NULL;
+ }
+
+#if STM32_I2S_USE_SPI1
+ if (&I2SD1 == i2sp)
+ rccDisableSPI1();
+#endif
+
+#if STM32_I2S_USE_SPI2
+ if (&I2SD2 == i2sp)
+ rccDisableSPI2();
+#endif
+
+#if STM32_I2S_USE_SPI3
+ if (&I2SD3 == i2sp)
+ rccDisableSPI3();
+#endif
+ }
+}
+
+/**
+ * @brief Starts a I2S data exchange.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_start_exchange(I2SDriver *i2sp) {
+ size_t size = i2sp->config->size;
+
+ /* In 32 bit modes the DMA has to perform double operations because fetches
+ are always performed using 16 bit accesses.
+ DATLEN CHLEN SIZE
+ 00 (16) 0 (16) 16
+ 00 (16) 1 (32) 16
+ 01 (24) X 32
+ 10 (32) X 32
+ 11 (NA) X NA
+ */
+ if ((i2sp->config->i2scfgr & SPI_I2SCFGR_DATLEN) != 0)
+ size *= 2;
+
+ /* RX DMA setup.*/
+ if (NULL != i2sp->dmarx) {
+ dmaStreamSetMode(i2sp->dmarx, i2sp->rxdmamode);
+ dmaStreamSetPeripheral(i2sp->dmarx, &i2sp->spi->DR);
+ dmaStreamSetMemory0(i2sp->dmarx, i2sp->config->rx_buffer);
+ dmaStreamSetTransactionSize(i2sp->dmarx, size);
+ dmaStreamEnable(i2sp->dmarx);
+ }
+
+ /* TX DMA setup.*/
+ if (NULL != i2sp->dmatx) {
+ dmaStreamSetMode(i2sp->dmatx, i2sp->txdmamode);
+ dmaStreamSetPeripheral(i2sp->dmatx, &i2sp->spi->DR);
+ dmaStreamSetMemory0(i2sp->dmatx, i2sp->config->tx_buffer);
+ dmaStreamSetTransactionSize(i2sp->dmatx, size);
+ dmaStreamEnable(i2sp->dmatx);
+ }
+
+ /* Starting transfer.*/
+ i2sp->spi->I2SCFGR |= SPI_I2SCFGR_I2SE;
+}
+
+/**
+ * @brief Stops the ongoing data exchange.
+ * @details The ongoing data exchange, if any, is stopped, if the driver
+ * was not active the function does nothing.
+ *
+ * @param[in] i2sp pointer to the @p I2SDriver object
+ *
+ * @notapi
+ */
+void i2s_lld_stop_exchange(I2SDriver *i2sp) {
+
+ /* Stop TX DMA, if enabled.*/
+ if (NULL != i2sp->dmatx) {
+ dmaStreamDisable(i2sp->dmatx);
+
+ /* From the RM: To switch off the I2S, by clearing I2SE, it is mandatory
+ to wait for TXE = 1 and BSY = 0.*/
+ while ((i2sp->spi->SR & (SPI_SR_TXE | SPI_SR_BSY)) != SPI_SR_TXE)
+ ;
+ }
+
+ /* Stop SPI/I2S peripheral.*/
+ i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
+
+ /* Stop RX DMA, if enabled.*/
+ if (NULL != i2sp->dmarx)
+ dmaStreamDisable(i2sp->dmarx);
+}
+
+#endif /* HAL_USE_I2S */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h new file mode 100644 index 0000000..acf92e1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_i2s_lld.h @@ -0,0 +1,371 @@ +/*
+ 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 SPIv2/hal_i2s_lld.h
+ * @brief STM32 I2S subsystem low level driver header.
+ *
+ * @addtogroup I2S
+ * @{
+ */
+
+#ifndef HAL_I2S_LLD_H
+#define HAL_I2S_LLD_H
+
+#if HAL_USE_I2S || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Static I2S modes
+ * @{
+ */
+#define STM32_I2S_MODE_SLAVE 0
+#define STM32_I2S_MODE_MASTER 1
+#define STM32_I2S_MODE_RX 2
+#define STM32_I2S_MODE_TX 4
+#define STM32_I2S_MODE_RXTX (STM32_I2S_MODE_RX | \
+ STM32_I2S_MODE_TX)
+/** @} */
+
+/**
+ * @name Mode checks
+ * @{
+ */
+#define STM32_I2S_IS_MASTER(mode) ((mode) & STM32_I2S_MODE_MASTER)
+#define STM32_I2S_RX_ENABLED(mode) ((mode) & STM32_I2S_MODE_RX)
+#define STM32_I2S_TX_ENABLED(mode) ((mode) & STM32_I2S_MODE_TX)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief I2S1 driver enable switch.
+ * @details If set to @p TRUE the support for I2S1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2S_USE_SPI1) || defined(__DOXYGEN__)
+#define STM32_I2S_USE_SPI1 FALSE
+#endif
+
+/**
+ * @brief I2S2 driver enable switch.
+ * @details If set to @p TRUE the support for I2S2 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2S_USE_SPI2) || defined(__DOXYGEN__)
+#define STM32_I2S_USE_SPI2 FALSE
+#endif
+
+/**
+ * @brief I2S3 driver enable switch.
+ * @details If set to @p TRUE the support for I2S3 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2S_USE_SPI3) || defined(__DOXYGEN__)
+#define STM32_I2S_USE_SPI3 FALSE
+#endif
+
+/**
+ * @brief I2S1 mode.
+ */
+#if !defined(STM32_I2S_SPI1_MODE) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI1_MODE (STM32_I2S_MODE_MASTER | \
+ STM32_I2S_MODE_RX)
+#endif
+
+/**
+ * @brief I2S2 mode.
+ */
+#if !defined(STM32_I2S_SPI2_MODE) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI2_MODE (STM32_I2S_MODE_MASTER | \
+ STM32_I2S_MODE_RX)
+#endif
+
+/**
+ * @brief I2S3 mode.
+ */
+#if !defined(STM32_I2S_SPI3_MODE) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI3_MODE (STM32_I2S_MODE_MASTER | \
+ STM32_I2S_MODE_RX)
+#endif
+
+/**
+ * @brief I2S1 interrupt priority level setting.
+ */
+#if !defined(STM32_I2S_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2S2 interrupt priority level setting.
+ */
+#if !defined(STM32_I2S_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2S3 interrupt priority level setting.
+ */
+#if !defined(STM32_I2S_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief I2S1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_I2S_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2S2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_I2S_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2S3 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_I2S_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2S_SPI3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief I2S DMA error hook.
+ */
+#if !defined(STM32_I2S_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_I2S_USE_SPI1 && !STM32_SPI1_SUPPORTS_I2S
+#error "SPI1 does not support I2S mode"
+#endif
+
+#if STM32_I2S_USE_SPI2 && !STM32_SPI2_SUPPORTS_I2S
+#error "SPI2 does not support I2S mode"
+#endif
+
+#if STM32_I2S_USE_SPI3 && !STM32_SPI3_SUPPORTS_I2S
+#error "SPI3 does not support I2S mode"
+#endif
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI1_MODE) && \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI1_MODE)
+#error "I2S1 RX and TX mode not supported in this driver implementation"
+#endif
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI2_MODE) && \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI2_MODE)
+#error "I2S2 RX and TX mode not supported in this driver implementation"
+#endif
+
+#if STM32_I2S_RX_ENABLED(STM32_I2S_SPI3_MODE) && \
+ STM32_I2S_TX_ENABLED(STM32_I2S_SPI3_MODE)
+#error "I2S3 RX and TX mode not supported in this driver implementation"
+#endif
+
+#if STM32_I2S_USE_SPI1 && !STM32_HAS_SPI1
+#error "SPI1 not present in the selected device"
+#endif
+
+#if STM32_I2S_USE_SPI2 && !STM32_HAS_SPI2
+#error "SPI2 not present in the selected device"
+#endif
+
+#if STM32_I2S_USE_SPI3 && !STM32_HAS_SPI3
+#error "SPI3 not present in the selected device"
+#endif
+
+#if !STM32_I2S_USE_SPI1 && !STM32_I2S_USE_SPI2 && !STM32_I2S_USE_SPI3
+#error "I2S driver activated but no SPI peripheral assigned"
+#endif
+
+#if STM32_I2S_USE_SPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI1"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI2"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2S_SPI3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI3"
+#endif
+
+#if STM32_I2S_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI1"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI2"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_I2S_SPI3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI3"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_I2S_USE_SPI1 && (!defined(STM32_I2S_SPI1_RX_DMA_STREAM) || \
+ !defined(STM32_I2S_SPI1_TX_DMA_STREAM))
+#error "SPI1 DMA streams not defined"
+#endif
+
+#if STM32_I2S_USE_SPI2 && (!defined(STM32_I2S_SPI2_RX_DMA_STREAM) || \
+ !defined(STM32_I2S_SPI2_TX_DMA_STREAM))
+#error "SPI2 DMA streams not defined"
+#endif
+
+#if STM32_I2S_USE_SPI3 && (!defined(STM32_I2S_SPI3_RX_DMA_STREAM) || \
+ !defined(STM32_I2S_SPI3_TX_DMA_STREAM))
+#error "SPI3 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_I2S_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 RX"
+#endif
+
+#if STM32_I2S_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 TX"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 RX"
+#endif
+
+#if STM32_I2S_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 TX"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 RX"
+#endif
+
+#if STM32_I2S_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2S_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 TX"
+#endif
+#endif /* STM32_ADVANCED_DMA */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the I2S driver structure.
+ */
+#define i2s_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /* Calculated part of the I2SCFGR register.*/ \
+ uint16_t cfg; \
+ /* Receive DMA stream or @p NULL.*/ \
+ const stm32_dma_stream_t *dmarx; \
+ /* Transmit DMA stream or @p NULL.*/ \
+ const stm32_dma_stream_t *dmatx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+
+/**
+ * @brief Low level fields of the I2S configuration structure.
+ */
+#define i2s_lld_config_fields \
+ /* Configuration of the I2SCFGR register. \
+ NOTE: See the STM32 reference manual, this register is used for \
+ the I2S configuration, the following bits must not be \
+ specified because handled directly by the driver: \
+ - I2SMOD \
+ - I2SE \
+ - I2SCFG \
+ */ \
+ int16_t i2scfgr; \
+ /* Configuration of the I2SPR register. \
+ NOTE: See the STM32 reference manual, this register is used for \
+ the I2S clock setup.*/ \
+ int16_t i2spr
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_I2S_USE_SPI1 && !defined(__DOXYGEN__)
+extern I2SDriver I2SD1;
+#endif
+
+#if STM32_I2S_USE_SPI2 && !defined(__DOXYGEN__)
+extern I2SDriver I2SD2;
+#endif
+
+#if STM32_I2S_USE_SPI3 && !defined(__DOXYGEN__)
+extern I2SDriver I2SD3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void i2s_lld_init(void);
+ void i2s_lld_start(I2SDriver *i2sp);
+ void i2s_lld_stop(I2SDriver *i2sp);
+ void i2s_lld_start_exchange(I2SDriver *i2sp);
+ void i2s_lld_stop_exchange(I2SDriver *i2sp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_I2S */
+
+#endif /* HAL_I2S_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c new file mode 100644 index 0000000..02bc9a0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.c @@ -0,0 +1,720 @@ +/*
+ 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 SPIv2/hal_spi_lld.c
+ * @brief STM32 SPI subsystem low level driver source.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define SPI1_RX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_RX_DMA_STREAM, \
+ STM32_SPI1_RX_DMA_CHN)
+
+#define SPI1_TX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_TX_DMA_STREAM, \
+ STM32_SPI1_TX_DMA_CHN)
+
+#define SPI2_RX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_RX_DMA_STREAM, \
+ STM32_SPI2_RX_DMA_CHN)
+
+#define SPI2_TX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_TX_DMA_STREAM, \
+ STM32_SPI2_TX_DMA_CHN)
+
+#define SPI3_RX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_RX_DMA_STREAM, \
+ STM32_SPI3_RX_DMA_CHN)
+
+#define SPI3_TX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_TX_DMA_STREAM, \
+ STM32_SPI3_TX_DMA_CHN)
+
+#define SPI4_RX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_RX_DMA_STREAM, \
+ STM32_SPI4_RX_DMA_CHN)
+
+#define SPI4_TX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_TX_DMA_STREAM, \
+ STM32_SPI4_TX_DMA_CHN)
+
+#define SPI5_RX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_RX_DMA_STREAM, \
+ STM32_SPI5_RX_DMA_CHN)
+
+#define SPI5_TX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_TX_DMA_STREAM, \
+ STM32_SPI5_TX_DMA_CHN)
+
+#define SPI6_RX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_RX_DMA_STREAM, \
+ STM32_SPI6_RX_DMA_CHN)
+
+#define SPI6_TX_DMA_STREAM \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_TX_DMA_STREAM, \
+ STM32_SPI6_TX_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SPI1 driver identifier.*/
+#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
+SPIDriver SPID1;
+#endif
+
+/** @brief SPI2 driver identifier.*/
+#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
+SPIDriver SPID2;
+#endif
+
+/** @brief SPI3 driver identifier.*/
+#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
+SPIDriver SPID3;
+#endif
+
+/** @brief SPI4 driver identifier.*/
+#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__)
+SPIDriver SPID4;
+#endif
+
+/** @brief SPI5 driver identifier.*/
+#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__)
+SPIDriver SPID5;
+#endif
+
+/** @brief SPI6 driver identifier.*/
+#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__)
+SPIDriver SPID6;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const uint16_t dummytx = 0xFFFFU;
+static uint16_t dummyrx;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Shared end-of-rx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (spip->config->circular) {
+ if ((flags & STM32_DMA_ISR_HTIF) != 0U) {
+ /* Half buffer interrupt.*/
+ _spi_isr_half_code(spip);
+ }
+ if ((flags & STM32_DMA_ISR_TCIF) != 0U) {
+ /* End buffer interrupt.*/
+ _spi_isr_full_code(spip);
+ }
+ }
+ else {
+ /* Stopping DMAs.*/
+ dmaStreamDisable(spip->dmatx);
+ dmaStreamDisable(spip->dmarx);
+
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+ }
+}
+
+/**
+ * @brief Shared end-of-tx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ (void)spip;
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)spip;
+ (void)flags;
+#endif
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SPI driver initialization.
+ *
+ * @notapi
+ */
+void spi_lld_init(void) {
+
+#if STM32_SPI_USE_SPI1
+ spiObjectInit(&SPID1);
+ SPID1.spi = SPI1;
+ SPID1.dmarx = NULL;
+ SPID1.dmatx = NULL;
+ SPID1.rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID1.txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI2
+ spiObjectInit(&SPID2);
+ SPID2.spi = SPI2;
+ SPID2.dmarx = NULL;
+ SPID2.dmatx = NULL;
+ SPID2.rxdmamode = STM32_DMA_CR_CHSEL(SPI2_RX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID2.txdmamode = STM32_DMA_CR_CHSEL(SPI2_TX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI3
+ spiObjectInit(&SPID3);
+ SPID3.spi = SPI3;
+ SPID3.dmarx = NULL;
+ SPID3.dmatx = NULL;
+ SPID3.rxdmamode = STM32_DMA_CR_CHSEL(SPI3_RX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID3.txdmamode = STM32_DMA_CR_CHSEL(SPI3_TX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI4
+ spiObjectInit(&SPID4);
+ SPID4.spi = SPI4;
+ SPID4.dmarx = NULL;
+ SPID4.dmatx = NULL;
+ SPID4.rxdmamode = STM32_DMA_CR_CHSEL(SPI4_RX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID4.txdmamode = STM32_DMA_CR_CHSEL(SPI4_TX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI5
+ spiObjectInit(&SPID5);
+ SPID5.spi = SPI5;
+ SPID5.dmarx = NULL;
+ SPID5.dmatx = NULL;
+ SPID5.rxdmamode = STM32_DMA_CR_CHSEL(SPI5_RX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID5.txdmamode = STM32_DMA_CR_CHSEL(SPI5_TX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+
+#if STM32_SPI_USE_SPI6
+ spiObjectInit(&SPID6);
+ SPID6.spi = SPI6;
+ SPID6.dmarx = NULL;
+ SPID6.dmatx = NULL;
+ SPID6.rxdmamode = STM32_DMA_CR_CHSEL(SPI6_RX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID6.txdmamode = STM32_DMA_CR_CHSEL(SPI6_TX_DMA_STREAM) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#endif
+}
+
+/**
+ * @brief Configures and activates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_start(SPIDriver *spip) {
+ uint32_t ds;
+
+ /* If in stopped state then enables the SPI and DMA clocks.*/
+ if (spip->state == SPI_STOP) {
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI1_RX_DMA_STREAM,
+ STM32_SPI_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI1_TX_DMA_STREAM,
+ STM32_SPI_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI1(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI1_RX);
+ dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI1_TX);
+#endif
+ }
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI2_RX_DMA_STREAM,
+ STM32_SPI_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI2_TX_DMA_STREAM,
+ STM32_SPI_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI2(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI2_RX);
+ dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI2_TX);
+#endif
+ }
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI3_RX_DMA_STREAM,
+ STM32_SPI_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI3_TX_DMA_STREAM,
+ STM32_SPI_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI3(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI3_RX);
+ dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI3_TX);
+#endif
+ }
+#endif
+#if STM32_SPI_USE_SPI4
+ if (&SPID4 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI4_RX_DMA_STREAM,
+ STM32_SPI_SPI4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI4_TX_DMA_STREAM,
+ STM32_SPI_SPI4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI4(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI4_RX);
+ dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI4_TX);
+#endif
+ }
+#endif
+#if STM32_SPI_USE_SPI5
+ if (&SPID5 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI5_RX_DMA_STREAM,
+ STM32_SPI_SPI5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI5_TX_DMA_STREAM,
+ STM32_SPI_SPI5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI5(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI5_RX);
+ dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI5_TX);
+#endif
+ }
+#endif
+#if STM32_SPI_USE_SPI6
+ if (&SPID6 == spip) {
+ spip->dmarx = dmaStreamAllocI(STM32_SPI_SPI6_RX_DMA_STREAM,
+ STM32_SPI_SPI6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmarx != NULL, "unable to allocate stream");
+ spip->dmatx = dmaStreamAllocI(STM32_SPI_SPI6_TX_DMA_STREAM,
+ STM32_SPI_SPI6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->dmatx != NULL, "unable to allocate stream");
+ rccEnableSPI6(true);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(spip->dmarx, STM32_DMAMUX1_SPI6_RX);
+ dmaSetRequestSource(spip->dmatx, STM32_DMAMUX1_SPI6_TX);
+#endif
+ }
+#endif
+
+ /* DMA setup.*/
+ dmaStreamSetPeripheral(spip->dmarx, &spip->spi->DR);
+ dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR);
+ }
+
+ /* Configuration-specific DMA setup.*/
+ ds = spip->config->cr2 & SPI_CR2_DS;
+ if (!ds || (ds <= (SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0))) {
+ /* Frame width is 8 bits or smaller.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ }
+ else {
+ /* Frame width is larger than 8 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ }
+
+ if (spip->config->circular) {
+ spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ }
+ else {
+ spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ }
+
+ /* SPI setup and enable.*/
+ spip->spi->CR1 &= ~SPI_CR1_SPE;
+ spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR;
+ spip->spi->CR2 = spip->config->cr2 | SPI_CR2_FRXTH | SPI_CR2_SSOE |
+ SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
+ spip->spi->CR1 |= SPI_CR1_SPE;
+}
+
+/**
+ * @brief Deactivates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_stop(SPIDriver *spip) {
+
+ /* If in ready state then disables the SPI clock.*/
+ if (spip->state == SPI_READY) {
+
+ /* SPI disable.*/
+ spip->spi->CR1 &= ~SPI_CR1_SPE;
+ spip->spi->CR1 = 0;
+ spip->spi->CR2 = 0;
+ dmaStreamFreeI(spip->dmarx);
+ dmaStreamFreeI(spip->dmatx);
+ spip->dmarx = NULL;
+ spip->dmatx = NULL;
+
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip)
+ rccDisableSPI1();
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip)
+ rccDisableSPI2();
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip)
+ rccDisableSPI3();
+#endif
+#if STM32_SPI_USE_SPI4
+ if (&SPID4 == spip)
+ rccDisableSPI4();
+#endif
+#if STM32_SPI_USE_SPI5
+ if (&SPID5 == spip)
+ rccDisableSPI5();
+#endif
+#if STM32_SPI_USE_SPI6
+ if (&SPID6 == spip)
+ rccDisableSPI6();
+#endif
+ }
+}
+
+#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
+/**
+ * @brief Asserts the slave select signal and prepares for transfers.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_select(SPIDriver *spip) {
+
+ /* No implementation on STM32.*/
+}
+
+/**
+ * @brief Deasserts the slave select signal.
+ * @details The previously selected peripheral is unselected.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_unselect(SPIDriver *spip) {
+
+ /* No implementation on STM32.*/
+}
+#endif
+
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This asynchronous function starts the transmission of a series of
+ * idle words on the SPI bus and ignores the received data.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be ignored
+ *
+ * @notapi
+ */
+void spi_lld_ignore(SPIDriver *spip, size_t n) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, &dummyrx);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
+
+ dmaStreamSetMemory0(spip->dmatx, &dummytx);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamSetMemory0(spip->dmatx, txbuf);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, &dummyrx);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
+
+ dmaStreamSetMemory0(spip->dmatx, txbuf);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ dmaStreamSetMemory0(spip->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(spip->dmarx, n);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamSetMemory0(spip->dmatx, &dummytx);
+ dmaStreamSetTransactionSize(spip->dmatx, n);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode);
+
+ dmaStreamEnable(spip->dmarx);
+ dmaStreamEnable(spip->dmatx);
+}
+
+#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Aborts the ongoing SPI operation, if any.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_abort(SPIDriver *spip) {
+
+ /* Stopping DMAs.*/
+ dmaStreamDisable(spip->dmatx);
+ dmaStreamDisable(spip->dmarx);
+}
+#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */
+
+/**
+ * @brief Exchanges one frame using a polled wait.
+ * @details This synchronous function exchanges one frame using a polled
+ * synchronization method. This function is useful when exchanging
+ * small amount of data on high speed channels, usually in this
+ * situation is much more efficient just wait for completion using
+ * polling than suspending the thread waiting for an interrupt.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] frame the data frame to send over the SPI bus
+ * @return The received data frame from the SPI bus.
+ */
+uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
+
+ /*
+ * Data register must be accessed with the appropriate data size.
+ * Byte size access (uint8_t *) for transactions that are <= 8-bit.
+ * Halfword size access (uint16_t) for transactions that are <= 8-bit.
+ */
+ if ((spip->config->cr2 & SPI_CR2_DS) <= (SPI_CR2_DS_2 |
+ SPI_CR2_DS_1 |
+ SPI_CR2_DS_0)) {
+ volatile uint8_t *spidr = (volatile uint8_t *)&spip->spi->DR;
+ *spidr = (uint8_t)frame;
+ while ((spip->spi->SR & SPI_SR_RXNE) == 0)
+ ;
+ return (uint16_t)*spidr;
+ }
+ else {
+ spip->spi->DR = frame;
+ while ((spip->spi->SR & SPI_SR_RXNE) == 0)
+ ;
+ return spip->spi->DR;
+ }
+}
+
+#endif /* HAL_USE_SPI */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h new file mode 100644 index 0000000..3ded6ed --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv2/hal_spi_lld.h @@ -0,0 +1,552 @@ +/*
+ 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 SPIv2/hal_spi_lld.h
+ * @brief STM32 SPI subsystem low level driver header.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef HAL_SPI_LLD_H
+#define HAL_SPI_LLD_H
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Circular mode support flag.
+ */
+#define SPI_SUPPORTS_CIRCULAR TRUE
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SPI1 driver enable switch.
+ * @details If set to @p TRUE the support for SPI1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI1 FALSE
+#endif
+
+/**
+ * @brief SPI2 driver enable switch.
+ * @details If set to @p TRUE the support for SPI2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI2 FALSE
+#endif
+
+/**
+ * @brief SPI3 driver enable switch.
+ * @details If set to @p TRUE the support for SPI3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI3 FALSE
+#endif
+
+/**
+ * @brief SPI4 driver enable switch.
+ * @details If set to @p TRUE the support for SPI4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI4 FALSE
+#endif
+
+/**
+ * @brief SPI5 driver enable switch.
+ * @details If set to @p TRUE the support for SPI5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI5 FALSE
+#endif
+
+/**
+ * @brief SPI6 driver enable switch.
+ * @details If set to @p TRUE the support for SPI6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI6 FALSE
+#endif
+
+/**
+ * @brief SPI1 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI2 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI3 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI4 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI4_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI5 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI5_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI6 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI6_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI4_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI5 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI5_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI6 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI6_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI DMA error hook.
+ */
+#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1
+#error "SPI1 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2
+#error "SPI2 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3
+#error "SPI3 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4
+#error "SPI4 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5
+#error "SPI5 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6
+#error "SPI6 not present in the selected device"
+#endif
+
+#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \
+ !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6
+#error "SPI driver activated but no SPI peripheral assigned"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI1"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI2"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI3"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI4"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI5"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI6"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI1"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI2"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI3"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI4"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI5"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI6"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI1_TX_DMA_STREAM))
+#error "SPI1 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI2_TX_DMA_STREAM))
+#error "SPI2 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI3_TX_DMA_STREAM))
+#error "SPI3 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI4_TX_DMA_STREAM))
+#error "SPI4 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI5_TX_DMA_STREAM))
+#error "SPI5 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI6_TX_DMA_STREAM))
+#error "SPI6 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI1 TX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI2 RX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI2 TX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI3 RX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI3 TX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI4 RX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI4 TX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI5 RX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI5 TX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI6_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI6 RX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI6_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to SPI6 TX"
+#endif
+
+/* Devices without DMAMUX require an additional check.*/
+#if STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 RX"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 TX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 RX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 TX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 RX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 TX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_RX_DMA_STREAM, STM32_SPI4_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI4 RX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI4_TX_DMA_STREAM, STM32_SPI4_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI4 TX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_RX_DMA_STREAM, STM32_SPI5_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI5 RX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI5_TX_DMA_STREAM, STM32_SPI5_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI5 TX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_RX_DMA_STREAM, STM32_SPI6_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI6 RX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI6_TX_DMA_STREAM, STM32_SPI6_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI6 TX"
+#endif
+
+#endif /* STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD
+#error "SPI_SELECT_MODE_LLD not supported by this driver"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level fields of the SPI driver structure.
+ */
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /* Receive DMA stream.*/ \
+ const stm32_dma_stream_t *dmarx; \
+ /* Transmit DMA stream.*/ \
+ const stm32_dma_stream_t *dmatx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+
+/**
+ * @brief Low level fields of the SPI configuration structure.
+ */
+#define spi_lld_config_fields \
+ /* SPI CR1 register initialization data.*/ \
+ uint16_t cr1; \
+ /* SPI CR2 register initialization data.*/ \
+ uint16_t cr2
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__)
+extern SPIDriver SPID1;
+#endif
+
+#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__)
+extern SPIDriver SPID2;
+#endif
+
+#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__)
+extern SPIDriver SPID3;
+#endif
+
+#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__)
+extern SPIDriver SPID4;
+#endif
+
+#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__)
+extern SPIDriver SPID5;
+#endif
+
+#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__)
+extern SPIDriver SPID6;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void spi_lld_init(void);
+ void spi_lld_start(SPIDriver *spip);
+ void spi_lld_stop(SPIDriver *spip);
+#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
+ void spi_lld_select(SPIDriver *spip);
+ void spi_lld_unselect(SPIDriver *spip);
+#endif
+ void spi_lld_ignore(SPIDriver *spip, size_t n);
+ void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf);
+ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
+ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
+ void spi_lld_abort(SPIDriver *spip);
+#endif
+ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SPI */
+
+#endif /* HAL_SPI_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk new file mode 100644 index 0000000..b29942c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c new file mode 100644 index 0000000..4a67c87 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.c @@ -0,0 +1,1140 @@ +/*
+ 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 SPIv3/hal_spi_lld.c
+ * @brief STM32 SPI subsystem low level driver source.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SPI1 driver identifier.*/
+#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
+SPIDriver SPID1;
+#endif
+
+/** @brief SPI2 driver identifier.*/
+#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
+SPIDriver SPID2;
+#endif
+
+/** @brief SPI3 driver identifier.*/
+#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
+SPIDriver SPID3;
+#endif
+
+/** @brief SPI4 driver identifier.*/
+#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__)
+SPIDriver SPID4;
+#endif
+
+/** @brief SPI5 driver identifier.*/
+#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__)
+SPIDriver SPID5;
+#endif
+
+/** @brief SPI6 driver identifier.*/
+#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__)
+SPIDriver SPID6;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const uint32_t dummytx = STM32_SPI_FILLER_PATTERN;
+static uint32_t dummyrx;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static void spi_lld_wait_complete(SPIDriver *spip) {
+
+ while ((spip->spi->CR1 & SPI_CR1_CSTART) != 0) {
+ }
+ spip->spi->IFCR = 0xFFFFFFFF;
+}
+
+#if defined(STM32_SPI_BDMA_REQUIRED)
+/**
+ * @brief Shared DMA end-of-rx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_bdma_rx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ if ((flags & STM32_BDMA_ISR_TEIF) != 0U) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (spip->config->circular) {
+ if ((flags & STM32_BDMA_ISR_HTIF) != 0U) {
+ /* Half buffer interrupt.*/
+ _spi_isr_half_code(spip);
+ }
+ if ((flags & STM32_BDMA_ISR_TCIF) != 0U) {
+ /* End buffer interrupt.*/
+ _spi_isr_full_code(spip);
+ }
+ }
+ else {
+ /* Stopping SPI.*/
+ spip->spi->CR1 |= SPI_CR1_CSUSP;
+
+ /* Stopping DMAs.*/
+ bdmaStreamDisable(spip->tx.bdma);
+ bdmaStreamDisable(spip->rx.bdma);
+
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+ }
+}
+
+/**
+ * @brief Shared BDMA end-of-tx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_bdma_tx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ (void)spip;
+ if ((flags & STM32_BDMA_ISR_TEIF) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)spip;
+ (void)flags;
+#endif
+}
+#endif /* defined(STM32_SPI_BDMA_REQUIRED) */
+
+#if defined(STM32_SPI_DMA_REQUIRED)
+/**
+ * @brief Shared DMA end-of-rx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_dma_rx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0U) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (spip->config->circular) {
+ if ((flags & STM32_DMA_ISR_HTIF) != 0U) {
+ /* Half buffer interrupt.*/
+ _spi_isr_half_code(spip);
+ }
+ if ((flags & STM32_DMA_ISR_TCIF) != 0U) {
+ /* End buffer interrupt.*/
+ _spi_isr_full_code(spip);
+ }
+ }
+ else {
+ /* Stopping SPI.*/
+ spip->spi->CR1 |= SPI_CR1_CSUSP;
+
+ /* Stopping DMAs.*/
+ dmaStreamDisable(spip->tx.dma);
+ dmaStreamDisable(spip->rx.dma);
+
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+ }
+}
+
+/**
+ * @brief Shared DMA end-of-tx service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void spi_lld_serve_dma_tx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ (void)spip;
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)spip;
+ (void)flags;
+#endif
+}
+#endif /* defined(STM32_SPI_DMA_REQUIRED) */
+
+/**
+ * @brief Shared SPI service routine.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ */
+static void spi_lld_serve_interrupt(SPIDriver *spip) {
+ uint32_t sr;
+
+ sr = spip->spi->SR & spip->spi->IER;
+ spip->spi->IFCR = sr;
+
+ if ((sr & SPI_SR_OVR) != 0U) {
+ /* CHTODO: fault notification.*/
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
+#if !defined(STM32_SPI1_SUPPRESS_ISR)
+#if !defined(STM32_SPI1_HANDLER)
+#error "STM32_SPI1_HANDLER not defined"
+#endif
+/**
+ * @brief SPI1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SPI1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_lld_serve_interrupt(&SPID1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_SPI1_SUPPRESS_ISR) */
+#endif /* STM32_SPI_USE_SPI1 */
+
+#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
+#if !defined(STM32_SPI2_SUPPRESS_ISR)
+#if !defined(STM32_SPI2_HANDLER)
+#error "STM32_SPI2_HANDLER not defined"
+#endif
+/**
+ * @brief SPI2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SPI2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_lld_serve_interrupt(&SPID2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_SPI2_SUPPRESS_ISR) */
+#endif /* STM32_SPI_USE_SPI2 */
+
+#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
+#if !defined(STM32_SPI3_SUPPRESS_ISR)
+#if !defined(STM32_SPI3_HANDLER)
+#error "STM32_SPI3_HANDLER not defined"
+#endif
+/**
+ * @brief SPI3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SPI3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_lld_serve_interrupt(&SPID3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_SPI3_SUPPRESS_ISR) */
+#endif /* STM32_SPI_USE_SPI3 */
+
+#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__)
+#if !defined(STM32_SPI4_SUPPRESS_ISR)
+#if !defined(STM32_SPI4_HANDLER)
+#error "STM32_SPI4_HANDLER not defined"
+#endif
+/**
+ * @brief SPI4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SPI4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_lld_serve_interrupt(&SPID4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_SPI4_SUPPRESS_ISR) */
+#endif /* STM32_SPI_USE_SPI4 */
+
+#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__)
+#if !defined(STM32_SPI5_SUPPRESS_ISR)
+#if !defined(STM32_SPI5_HANDLER)
+#error "STM32_SPI5_HANDLER not defined"
+#endif
+/**
+ * @brief SPI5 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SPI5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_lld_serve_interrupt(&SPID5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_SPI5_SUPPRESS_ISR) */
+#endif /* STM32_SPI_USE_SPI5 */
+
+#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__)
+#if !defined(STM32_SPI6_SUPPRESS_ISR)
+#if !defined(STM32_SPI6_HANDLER)
+#error "STM32_SPI6_HANDLER not defined"
+#endif
+/**
+ * @brief SPI6 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_SPI6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_lld_serve_interrupt(&SPID6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_SPI6_SUPPRESS_ISR) */
+#endif /* STM32_SPI_USE_SPI6 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SPI driver initialization.
+ *
+ * @notapi
+ */
+void spi_lld_init(void) {
+
+#if STM32_SPI_USE_SPI1
+ spiObjectInit(&SPID1);
+ SPID1.spi = SPI1;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ SPID1.is_bdma = false;
+#endif
+ SPID1.rx.dma = NULL;
+ SPID1.tx.dma = NULL;
+ SPID1.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID1.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#if !defined(STM32_SPI1_SUPPRESS_ISR)
+ nvicEnableVector(STM32_SPI1_NUMBER, STM32_SPI_SPI1_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_SPI_USE_SPI2
+ spiObjectInit(&SPID2);
+ SPID2.spi = SPI2;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ SPID2.is_bdma = false;
+#endif
+ SPID2.rx.dma = NULL;
+ SPID2.tx.dma = NULL;
+ SPID2.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID2.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#if !defined(STM32_SPI2_SUPPRESS_ISR)
+ nvicEnableVector(STM32_SPI2_NUMBER, STM32_SPI_SPI2_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_SPI_USE_SPI3
+ spiObjectInit(&SPID3);
+ SPID3.spi = SPI3;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ SPID3.is_bdma = false;
+#endif
+ SPID3.rx.dma = NULL;
+ SPID3.tx.dma = NULL;
+ SPID3.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID3.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#if !defined(STM32_SPI3_SUPPRESS_ISR)
+ nvicEnableVector(STM32_SPI3_NUMBER, STM32_SPI_SPI3_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_SPI_USE_SPI4
+ spiObjectInit(&SPID4);
+ SPID4.spi = SPI4;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ SPID4.is_bdma = false;
+#endif
+ SPID4.rx.dma = NULL;
+ SPID4.tx.dma = NULL;
+ SPID4.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID4.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#if !defined(STM32_SPI4_SUPPRESS_ISR)
+ nvicEnableVector(STM32_SPI4_NUMBER, STM32_SPI_SPI4_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_SPI_USE_SPI5
+ spiObjectInit(&SPID5);
+ SPID5.spi = SPI5;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ SPID5.is_bdma = false;
+#endif
+ SPID5.rx.dma = NULL;
+ SPID5.tx.dma = NULL;
+ SPID5.rxdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID5.txdmamode = STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+#if !defined(STM32_SPI5_SUPPRESS_ISR)
+ nvicEnableVector(STM32_SPI5_NUMBER, STM32_SPI_SPI5_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_SPI_USE_SPI6
+ spiObjectInit(&SPID6);
+ SPID6.spi = SPI6;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ SPID6.is_bdma = true;
+#endif
+ SPID6.rx.bdma = NULL;
+ SPID6.tx.bdma = NULL;
+ SPID6.rxdmamode = STM32_BDMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
+ STM32_BDMA_CR_DIR_P2M |
+ STM32_BDMA_CR_TCIE |
+ STM32_BDMA_CR_TEIE;
+ SPID6.txdmamode = STM32_BDMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
+ STM32_BDMA_CR_DIR_M2P |
+ STM32_BDMA_CR_TEIE;
+#if !defined(STM32_SPI6_SUPPRESS_ISR)
+ nvicEnableVector(STM32_SPI6_NUMBER, STM32_SPI_SPI6_IRQ_PRIORITY);
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_start(SPIDriver *spip) {
+ uint32_t dsize;
+
+ /* If in stopped state then enables the SPI and DMA clocks.*/
+ if (spip->state == SPI_STOP) {
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip) {
+ spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI1_RX_DMA_STREAM,
+ STM32_SPI_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream");
+ spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI1_TX_DMA_STREAM,
+ STM32_SPI_SPI1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream");
+ rccEnableSPI1(true);
+ dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI1_RX);
+ dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI1_TX);
+ }
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip) {
+ spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI2_RX_DMA_STREAM,
+ STM32_SPI_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream");
+ spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI2_TX_DMA_STREAM,
+ STM32_SPI_SPI2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream");
+ rccEnableSPI2(true);
+ dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI2_RX);
+ dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI2_TX);
+ }
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip) {
+ spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI3_RX_DMA_STREAM,
+ STM32_SPI_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream");
+ spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI3_TX_DMA_STREAM,
+ STM32_SPI_SPI3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream");
+ rccEnableSPI3(true);
+ dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI3_RX);
+ dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI3_TX);
+ }
+#endif
+#if STM32_SPI_USE_SPI4
+ if (&SPID4 == spip) {
+ spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI4_RX_DMA_STREAM,
+ STM32_SPI_SPI4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream");
+ spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI4_TX_DMA_STREAM,
+ STM32_SPI_SPI4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream");
+ rccEnableSPI4(true);
+ dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI4_RX);
+ dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI4_TX);
+ }
+#endif
+#if STM32_SPI_USE_SPI5
+ if (&SPID5 == spip) {
+ spip->rx.dma = dmaStreamAllocI(STM32_SPI_SPI5_RX_DMA_STREAM,
+ STM32_SPI_SPI5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream");
+ spip->tx.dma = dmaStreamAllocI(STM32_SPI_SPI5_TX_DMA_STREAM,
+ STM32_SPI_SPI5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_dma_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream");
+ rccEnableSPI5(true);
+ dmaSetRequestSource(spip->rx.dma, STM32_DMAMUX1_SPI5_RX);
+ dmaSetRequestSource(spip->tx.dma, STM32_DMAMUX1_SPI5_TX);
+ }
+#endif
+#if STM32_SPI_USE_SPI6
+ if (&SPID6 == spip) {
+ spip->rx.bdma = bdmaStreamAllocI(STM32_SPI_SPI6_RX_BDMA_STREAM,
+ STM32_SPI_SPI6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_bdma_rx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->rx.dma != NULL, "unable to allocate stream");
+ spip->tx.bdma = bdmaStreamAllocI(STM32_SPI_SPI6_TX_BDMA_STREAM,
+ STM32_SPI_SPI6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)spi_lld_serve_bdma_tx_interrupt,
+ (void *)spip);
+ osalDbgAssert(spip->tx.dma != NULL, "unable to allocate stream");
+ rccEnableSPI6(true);
+ bdmaSetRequestSource(spip->rx.bdma, STM32_DMAMUX2_SPI6_RX);
+ bdmaSetRequestSource(spip->tx.bdma, STM32_DMAMUX2_SPI6_TX);
+ }
+#endif
+
+ /* DMA setup.*/
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamSetPeripheral(spip->rx.bdma, &spip->spi->RXDR);
+ bdmaStreamSetPeripheral(spip->tx.bdma, &spip->spi->TXDR);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamSetPeripheral(spip->rx.dma, &spip->spi->RXDR);
+ dmaStreamSetPeripheral(spip->tx.dma, &spip->spi->TXDR);
+ }
+#endif
+ }
+
+ /* Configuration-specific DMA setup.*/
+ dsize = (spip->config->cfg1 & SPI_CFG1_DSIZE_Msk) + 1U;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ if (dsize <= 8U) {
+ /* Frame width is between 4 and 8 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) |
+ STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE;
+ spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) |
+ STM32_BDMA_CR_PSIZE_BYTE | STM32_BDMA_CR_MSIZE_BYTE;
+ }
+ else if (dsize <= 16U) {
+ /* Frame width is between 9 and 16 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) |
+ STM32_BDMA_CR_PSIZE_HWORD | STM32_BDMA_CR_MSIZE_HWORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) |
+ STM32_BDMA_CR_PSIZE_HWORD | STM32_BDMA_CR_MSIZE_HWORD;
+ }
+ else {
+ /* Frame width is between 16 and 32 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_BDMA_CR_SIZE_MASK) |
+ STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_WORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_BDMA_CR_SIZE_MASK) |
+ STM32_BDMA_CR_PSIZE_WORD | STM32_BDMA_CR_MSIZE_WORD;
+ }
+ if (spip->config->circular) {
+ spip->rxdmamode |= (STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE);
+ spip->txdmamode |= (STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE);
+ }
+ else {
+ spip->rxdmamode &= ~(STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE);
+ spip->txdmamode &= ~(STM32_BDMA_CR_CIRC | STM32_BDMA_CR_HTIE);
+ }
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ if (dsize <= 8U) {
+ /* Frame width is between 4 and 8 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ }
+ else if (dsize <= 16U) {
+ /* Frame width is between 9 and 16 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ }
+ else {
+ /* Frame width is between 16 and 32 bits.*/
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+ }
+ if (spip->config->circular) {
+ spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ }
+ else {
+ spip->rxdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ spip->txdmamode &= ~(STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE);
+ }
+ }
+#endif
+
+ /* SPI setup and enable.*/
+ spip->spi->CR1 &= ~SPI_CR1_SPE;
+ spip->spi->CR1 = SPI_CR1_MASRX;
+ spip->spi->CR2 = 0U;
+ spip->spi->CFG1 = (spip->config->cfg1 & ~SPI_CFG1_FTHLV_Msk) |
+ SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN;
+ spip->spi->CFG2 = (spip->config->cfg2 | SPI_CFG2_MASTER | SPI_CFG2_SSOE) &
+ ~SPI_CFG2_COMM_Msk;
+ spip->spi->IER = SPI_IER_OVRIE;
+ spip->spi->IFCR = 0xFFFFFFFFU;
+ spip->spi->CR1 |= SPI_CR1_SPE;
+}
+
+/**
+ * @brief Deactivates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_stop(SPIDriver *spip) {
+
+ /* If in ready state then disables the SPI clock.*/
+ if (spip->state == SPI_READY) {
+
+ /* SPI disable.*/
+ spip->spi->CR1 &= ~SPI_CR1_SPE;
+ spip->spi->CR1 = 0U;
+ spip->spi->CR2 = 0U;
+ spip->spi->CFG1 = 0U;
+ spip->spi->CFG2 = 0U;
+ spip->spi->IER = 0U;
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamFreeI(spip->rx.bdma);
+ bdmaStreamFreeI(spip->tx.bdma);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamFreeI(spip->rx.dma);
+ dmaStreamFreeI(spip->tx.dma);
+ }
+#endif
+
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip)
+ rccDisableSPI1();
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip)
+ rccDisableSPI2();
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip)
+ rccDisableSPI3();
+#endif
+#if STM32_SPI_USE_SPI4
+ if (&SPID4 == spip)
+ rccDisableSPI4();
+#endif
+#if STM32_SPI_USE_SPI5
+ if (&SPID5 == spip)
+ rccDisableSPI5();
+#endif
+#if STM32_SPI_USE_SPI6
+ if (&SPID6 == spip)
+ rccDisableSPI6();
+#endif
+ }
+}
+
+#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
+/**
+ * @brief Asserts the slave select signal and prepares for transfers.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_select(SPIDriver *spip) {
+
+ /* No implementation on STM32.*/
+}
+
+/**
+ * @brief Deasserts the slave select signal.
+ * @details The previously selected peripheral is unselected.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_unselect(SPIDriver *spip) {
+
+ /* No implementation on STM32.*/
+}
+#endif
+
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This asynchronous function starts the transmission of a series of
+ * idle words on the SPI bus and ignores the received data.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be ignored
+ *
+ * @notapi
+ */
+void spi_lld_ignore(SPIDriver *spip, size_t n) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamSetMemory(spip->rx.bdma, &dummyrx);
+ bdmaStreamSetTransactionSize(spip->rx.bdma, n);
+ bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode);
+
+ bdmaStreamSetMemory(spip->tx.bdma, &dummytx);
+ bdmaStreamSetTransactionSize(spip->tx.bdma, n);
+ bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode);
+
+ bdmaStreamEnable(spip->rx.bdma);
+ bdmaStreamEnable(spip->tx.bdma);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamSetMemory0(spip->rx.dma, &dummyrx);
+ dmaStreamSetTransactionSize(spip->rx.dma, n);
+ dmaStreamSetMode(spip->rx.dma, spip->rxdmamode);
+
+ dmaStreamSetMemory0(spip->tx.dma, &dummytx);
+ dmaStreamSetTransactionSize(spip->tx.dma, n);
+ dmaStreamSetMode(spip->tx.dma, spip->txdmamode);
+
+ dmaStreamEnable(spip->rx.dma);
+ dmaStreamEnable(spip->tx.dma);
+ }
+#endif
+
+ spip->spi->CR1 |= SPI_CR1_CSTART;
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ spi_lld_wait_complete(spip);
+
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamSetMemory(spip->rx.bdma, rxbuf);
+ bdmaStreamSetTransactionSize(spip->rx.bdma, n);
+ bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode | STM32_BDMA_CR_MINC);
+
+ bdmaStreamSetMemory(spip->tx.bdma, txbuf);
+ bdmaStreamSetTransactionSize(spip->tx.bdma, n);
+ bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode | STM32_BDMA_CR_MINC);
+
+ bdmaStreamEnable(spip->rx.bdma);
+ bdmaStreamEnable(spip->tx.bdma);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamSetMemory0(spip->rx.dma, rxbuf);
+ dmaStreamSetTransactionSize(spip->rx.dma, n);
+ dmaStreamSetMode(spip->rx.dma, spip->rxdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamSetMemory0(spip->tx.dma, txbuf);
+ dmaStreamSetTransactionSize(spip->tx.dma, n);
+ dmaStreamSetMode(spip->tx.dma, spip->txdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamEnable(spip->rx.dma);
+ dmaStreamEnable(spip->tx.dma);
+ }
+#endif
+
+ spip->spi->CR1 |= SPI_CR1_CSTART;
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ spi_lld_wait_complete(spip);
+
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamSetMemory(spip->rx.bdma, &dummyrx);
+ bdmaStreamSetTransactionSize(spip->rx.bdma, n);
+ bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode);
+
+ bdmaStreamSetMemory(spip->tx.bdma, txbuf);
+ bdmaStreamSetTransactionSize(spip->tx.bdma, n);
+ bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode | STM32_BDMA_CR_MINC);
+
+ bdmaStreamEnable(spip->rx.bdma);
+ bdmaStreamEnable(spip->tx.bdma);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamSetMemory0(spip->rx.dma, &dummyrx);
+ dmaStreamSetTransactionSize(spip->rx.dma, n);
+ dmaStreamSetMode(spip->rx.dma, spip->rxdmamode);
+
+ dmaStreamSetMemory0(spip->tx.dma, txbuf);
+ dmaStreamSetTransactionSize(spip->tx.dma, n);
+ dmaStreamSetMode(spip->tx.dma, spip->txdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamEnable(spip->rx.dma);
+ dmaStreamEnable(spip->tx.dma);
+ }
+#endif
+
+ spip->spi->CR1 |= SPI_CR1_CSTART;
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
+
+ osalDbgAssert(n < 65536, "unsupported DMA transfer size");
+
+ spi_lld_wait_complete(spip);
+
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamSetMemory(spip->rx.bdma, rxbuf);
+ bdmaStreamSetTransactionSize(spip->rx.bdma, n);
+ bdmaStreamSetMode(spip->rx.bdma, spip->rxdmamode | STM32_BDMA_CR_MINC);
+
+ bdmaStreamSetMemory(spip->tx.bdma, &dummytx);
+ bdmaStreamSetTransactionSize(spip->tx.bdma, n);
+ bdmaStreamSetMode(spip->tx.bdma, spip->txdmamode);
+
+ bdmaStreamEnable(spip->rx.bdma);
+ bdmaStreamEnable(spip->tx.bdma);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamSetMemory0(spip->rx.dma, rxbuf);
+ dmaStreamSetTransactionSize(spip->rx.dma, n);
+ dmaStreamSetMode(spip->rx.dma, spip->rxdmamode | STM32_DMA_CR_MINC);
+
+ dmaStreamSetMemory0(spip->tx.dma, &dummytx);
+ dmaStreamSetTransactionSize(spip->tx.dma, n);
+ dmaStreamSetMode(spip->tx.dma, spip->txdmamode);
+
+ dmaStreamEnable(spip->rx.dma);
+ dmaStreamEnable(spip->tx.dma);
+ }
+#endif
+
+ spip->spi->CR1 |= SPI_CR1_CSTART;
+}
+
+#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Aborts the ongoing SPI operation, if any.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_abort(SPIDriver *spip) {
+
+ /* Stopping SPI.*/
+ spip->spi->CR1 |= SPI_CR1_CSUSP;
+
+ spi_lld_wait_complete(spip);
+
+ /* Stopping DMAs.*/
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ if (spip->is_bdma)
+#endif
+#if defined(STM32_SPI_BDMA_REQUIRED)
+ {
+ bdmaStreamDisable(spip->tx.bdma);
+ bdmaStreamDisable(spip->rx.bdma);
+ }
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+ else
+#endif
+#if defined(STM32_SPI_DMA_REQUIRED)
+ {
+ dmaStreamDisable(spip->tx.dma);
+ dmaStreamDisable(spip->rx.dma);
+ }
+#endif
+}
+#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */
+
+/**
+ * @brief Exchanges one frame using a polled wait.
+ * @details This synchronous function exchanges one frame using a polled
+ * synchronization method. This function is useful when exchanging
+ * small amount of data on high speed channels, usually in this
+ * situation is much more efficient just wait for completion using
+ * polling than suspending the thread waiting for an interrupt.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] frame the data frame to send over the SPI bus
+ * @return The received data frame from the SPI bus.
+ *
+ * @notapi
+ */
+uint32_t spi_lld_polled_exchange(SPIDriver *spip, uint32_t frame) {
+ uint32_t dsize = (spip->spi->CFG1 & SPI_CFG1_DSIZE_Msk) + 1U;
+ uint32_t rxframe;
+
+ spi_lld_wait_complete(spip);
+
+ spip->spi->CR1 |= SPI_CR1_CSTART;
+
+ /* wait for room in TX FIFO.*/
+ while ((spip->spi->SR & SPI_SR_TXP) == 0U)
+ ;
+
+ /* Data register must be accessed with the appropriate data size.
+ Byte size access (uint8_t *) for transactions that are <= 8-bit etc.*/
+ if (dsize <= 8U) {
+ /* Frame width is between 4 and 8 bits.*/
+ volatile uint8_t *txdrp8 = (volatile uint8_t *)&spip->spi->TXDR;
+ volatile uint8_t *rxdrp8 = (volatile uint8_t *)&spip->spi->RXDR;
+ *txdrp8 = (uint8_t)frame;
+ while ((spip->spi->SR & SPI_SR_RXP) == 0U)
+ ;
+ rxframe = (uint32_t)*rxdrp8;
+ }
+ else if (dsize <= 16U) {
+ /* Frame width is between 9 and 16 bits.*/
+ volatile uint16_t *txdrp16 = (volatile uint16_t *)&spip->spi->TXDR;
+ volatile uint16_t *rxdrp16 = (volatile uint16_t *)&spip->spi->RXDR;
+ *txdrp16 = (uint16_t)frame;
+ while ((spip->spi->SR & SPI_SR_RXP) == 0U)
+ ;
+ rxframe = (uint32_t)*rxdrp16;
+ }
+ else {
+ /* Frame width is between 16 and 32 bits.*/
+ spip->spi->TXDR = frame;
+ while ((spip->spi->SR & SPI_SR_RXP) == 0U)
+ ;
+ rxframe = spip->spi->RXDR;
+ }
+
+ spip->spi->CR1 |= SPI_CR1_CSUSP;
+
+ return rxframe;
+}
+
+#endif /* HAL_USE_SPI */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h new file mode 100644 index 0000000..c906524 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/SPIv3/hal_spi_lld.h @@ -0,0 +1,590 @@ +/*
+ 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 SPIv3/hal_spi_lld.h
+ * @brief STM32 SPI subsystem low level driver header.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef HAL_SPI_LLD_H
+#define HAL_SPI_LLD_H
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Circular mode support flag.
+ */
+#define SPI_SUPPORTS_CIRCULAR TRUE
+
+/**
+ * @name Register helpers not found in ST headers
+ * @{
+ */
+#define SPI_CFG1_MBR_VALUE(n) ((n) << SPI_CFG1_MBR_Pos)
+#define SPI_CFG1_MBR_DIV2 SPI_CFG1_MBR_VALUE(0)
+#define SPI_CFG1_MBR_DIV4 SPI_CFG1_MBR_VALUE(1)
+#define SPI_CFG1_MBR_DIV8 SPI_CFG1_MBR_VALUE(2)
+#define SPI_CFG1_MBR_DIV16 SPI_CFG1_MBR_VALUE(3)
+#define SPI_CFG1_MBR_DIV32 SPI_CFG1_MBR_VALUE(4)
+#define SPI_CFG1_MBR_DIV64 SPI_CFG1_MBR_VALUE(5)
+#define SPI_CFG1_MBR_DIV128 SPI_CFG1_MBR_VALUE(6)
+#define SPI_CFG1_MBR_DIV256 SPI_CFG1_MBR_VALUE(7)
+#define SPI_CFG1_CRCSIZE_VALUE(n) ((n) << SPI_CFG1_CRCSIZE_Pos)
+#define SPI_CFG1_UDRDET_VALUE(n) ((n) << SPI_CFG1_UDRDET_Pos)
+#define SPI_CFG1_UDRCFG_VALUE(n) ((n) << SPI_CFG1_UDRCFG_Pos)
+#define SPI_CFG1_FTHLV_VALUE(n) ((n) << SPI_CFG1_FTHLV_Pos)
+#define SPI_CFG1_DSIZE_VALUE(n) ((n) << SPI_CFG1_DSIZE_Pos)
+
+#define SPI_CFG2_SP_VALUE(n) ((n) << SPI_CFG2_SP_Pos)
+#define SPI_CFG2_COMM_VALUE(n) ((n) << SPI_CFG2_COMM_Pos)
+#define SPI_CFG2_COMM_FULL_DUPLEX SPI_CFG2_COMM_VALUE(0)
+#define SPI_CFG2_COMM_TRANSMITTER SPI_CFG2_COMM_VALUE(1)
+#define SPI_CFG2_COMM_RECEIVER SPI_CFG2_COMM_VALUE(2)
+#define SPI_CFG2_COMM_HALF_DUPLEX SPI_CFG2_COMM_VALUE(3)
+#define SPI_CFG2_MIDI_VALUE(n) ((n) << SPI_CFG2_MIDI_Pos)
+#define SPI_CFG2_MSSI_VALUE(n) ((n) << SPI_CFG2_MSSI_Pos)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SPI1 driver enable switch.
+ * @details If set to @p TRUE the support for SPI1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI1) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI1 FALSE
+#endif
+
+/**
+ * @brief SPI2 driver enable switch.
+ * @details If set to @p TRUE the support for SPI2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI2) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI2 FALSE
+#endif
+
+/**
+ * @brief SPI3 driver enable switch.
+ * @details If set to @p TRUE the support for SPI3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI3) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI3 FALSE
+#endif
+
+/**
+ * @brief SPI4 driver enable switch.
+ * @details If set to @p TRUE the support for SPI4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI4) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI4 FALSE
+#endif
+
+/**
+ * @brief SPI5 driver enable switch.
+ * @details If set to @p TRUE the support for SPI5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI5) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI5 FALSE
+#endif
+
+/**
+ * @brief SPI6 driver enable switch.
+ * @details If set to @p TRUE the support for SPI6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SPI_USE_SPI6) || defined(__DOXYGEN__)
+#define STM32_SPI_USE_SPI6 FALSE
+#endif
+
+/**
+ * @brief Filler pattern used when there is nothing to transmit.
+ */
+#if !defined(STM32_SPI_FILLER_PATTERN) || defined(__DOXYGEN__)
+#define STM32_SPI_FILLER_PATTERN 0xFFFFFFFFU
+#endif
+
+/**
+ * @brief SPI1 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI2 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI3 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI4 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI4_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI5 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI5_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI6 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI6_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI6_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI4_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI5 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI5_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI5_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI6 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
+ */
+#if !defined(STM32_SPI_SPI6_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI6_DMA_PRIORITY 1
+#endif
+
+/**
+ * @brief SPI DMA error hook.
+ */
+#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 && !STM32_HAS_SPI1
+#error "SPI1 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI2 && !STM32_HAS_SPI2
+#error "SPI2 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI3 && !STM32_HAS_SPI3
+#error "SPI3 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI4 && !STM32_HAS_SPI4
+#error "SPI4 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI5 && !STM32_HAS_SPI5
+#error "SPI5 not present in the selected device"
+#endif
+
+#if STM32_SPI_USE_SPI6 && !STM32_HAS_SPI6
+#error "SPI6 not present in the selected device"
+#endif
+
+#if !STM32_SPI_USE_SPI1 && !STM32_SPI_USE_SPI2 && !STM32_SPI_USE_SPI3 && \
+ !STM32_SPI_USE_SPI4 && !STM32_SPI_USE_SPI5 && !STM32_SPI_USE_SPI6
+#error "SPI driver activated but no SPI peripheral assigned"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI1"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI2"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI3"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI4"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI5"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SPI_SPI6_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to SPI6"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_SPI_USE_SPI1 && (!defined(STM32_SPI_SPI1_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI1_TX_DMA_STREAM))
+#error "SPI1 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI2 && (!defined(STM32_SPI_SPI2_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI2_TX_DMA_STREAM))
+#error "SPI2 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI3 && (!defined(STM32_SPI_SPI3_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI3_TX_DMA_STREAM))
+#error "SPI3 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI4 && (!defined(STM32_SPI_SPI4_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI4_TX_DMA_STREAM))
+#error "SPI4 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI5 && (!defined(STM32_SPI_SPI5_RX_DMA_STREAM) || \
+ !defined(STM32_SPI_SPI5_TX_DMA_STREAM))
+#error "SPI5 DMA streams not defined"
+#endif
+
+#if STM32_SPI_USE_SPI6 && (!defined(STM32_SPI_SPI6_RX_BDMA_STREAM) || \
+ !defined(STM32_SPI_SPI6_TX_BDMA_STREAM))
+#error "SPI6 BDMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA streams.*/
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI1 RX"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI1 TX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI2 RX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI2 TX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI3 RX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI3 TX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI4 RX"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI4_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI4 TX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_RX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI5 RX"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_SPI_SPI5_TX_DMA_STREAM)
+#error "Invalid DMA stream assigned to SPI5 TX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_BDMA_IS_VALID_STREAM(STM32_SPI_SPI6_RX_BDMA_STREAM)
+#error "Invalid BDMA stream assigned to SPI6 RX"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_BDMA_IS_VALID_STREAM(STM32_SPI_SPI6_TX_BDMA_STREAM)
+#error "Invalid BDMA stream assigned to SPI6 TX"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI1"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI2"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI3"
+#endif
+
+#if STM32_SPI_USE_SPI4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI4"
+#endif
+
+#if STM32_SPI_USE_SPI5 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI5_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI5"
+#endif
+
+#if STM32_SPI_USE_SPI6 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_SPI_SPI6_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to SPI6"
+#endif
+
+#if STM32_SPI_USE_SPI1 || STM32_SPI_USE_SPI2 || STM32_SPI_USE_SPI1 || \
+ STM32_SPI_USE_SPI4 || STM32_SPI_USE_SPI5
+#define STM32_SPI_DMA_REQUIRED
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+#endif
+
+#if STM32_SPI_USE_SPI6
+#define STM32_SPI_BDMA_REQUIRED
+#if !defined(STM32_BDMA_REQUIRED)
+#define STM32_BDMA_REQUIRED
+#endif
+#endif
+
+#if SPI_SELECT_MODE == SPI_SELECT_MODE_LLD
+#error "SPI_SELECT_MODE_LLD not supported by this driver"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+#if (defined(STM32_SPI_DMA_REQUIRED) && \
+ defined(STM32_SPI_BDMA_REQUIRED)) || defined(__DOXYGEN__)
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /** DMA type for this instance.*/ \
+ bool is_bdma; \
+ /** Union of the RX DMA streams.*/ \
+ union { \
+ /* Receive DMA stream.*/ \
+ const stm32_dma_stream_t *dma; \
+ /* Receive BDMA stream.*/ \
+ const stm32_bdma_stream_t *bdma; \
+ } rx; \
+ /* Union of the TX DMA streams.*/ \
+ union { \
+ /* Transmit DMA stream.*/ \
+ const stm32_dma_stream_t *dma; \
+ /* Transmit DMA stream.*/ \
+ const stm32_bdma_stream_t *bdma; \
+ } tx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+#endif
+
+#if defined(STM32_SPI_DMA_REQUIRED) && !defined(STM32_SPI_BDMA_REQUIRED)
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /** Union of the RX DMA streams.*/ \
+ union { \
+ /* Receive DMA stream.*/ \
+ const stm32_dma_stream_t *dma; \
+ } rx; \
+ /* Union of the TX DMA streams.*/ \
+ union { \
+ /* Transmit DMA stream.*/ \
+ const stm32_dma_stream_t *dma; \
+ } tx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+#endif
+
+#if !defined(STM32_SPI_DMA_REQUIRED) && defined(STM32_SPI_BDMA_REQUIRED)
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ SPI_TypeDef *spi; \
+ /** Union of the RX DMA streams.*/ \
+ union { \
+ /* Receive BDMA stream.*/ \
+ const stm32_bdma_stream_t *bdma; \
+ } rx; \
+ /* Union of the TX DMA streams.*/ \
+ union { \
+ /* Transmit DMA stream.*/ \
+ const stm32_bdma_stream_t *bdma; \
+ } tx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode
+#endif
+
+/**
+ * @brief Low level fields of the SPI configuration structure.
+ */
+#define spi_lld_config_fields \
+ /* SPI CFG1 register initialization data.*/ \
+ uint32_t cfg1; \
+ /* SPI CFG2 register initialization data.*/ \
+ uint32_t cfg2
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SPI_USE_SPI1 && !defined(__DOXYGEN__)
+extern SPIDriver SPID1;
+#endif
+
+#if STM32_SPI_USE_SPI2 && !defined(__DOXYGEN__)
+extern SPIDriver SPID2;
+#endif
+
+#if STM32_SPI_USE_SPI3 && !defined(__DOXYGEN__)
+extern SPIDriver SPID3;
+#endif
+
+#if STM32_SPI_USE_SPI4 && !defined(__DOXYGEN__)
+extern SPIDriver SPID4;
+#endif
+
+#if STM32_SPI_USE_SPI5 && !defined(__DOXYGEN__)
+extern SPIDriver SPID5;
+#endif
+
+#if STM32_SPI_USE_SPI6 && !defined(__DOXYGEN__)
+extern SPIDriver SPID6;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void spi_lld_init(void);
+ void spi_lld_start(SPIDriver *spip);
+ void spi_lld_stop(SPIDriver *spip);
+#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined(__DOXYGEN__)
+ void spi_lld_select(SPIDriver *spip);
+ void spi_lld_unselect(SPIDriver *spip);
+#endif
+ void spi_lld_ignore(SPIDriver *spip, size_t n);
+ void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf);
+ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
+ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
+ void spi_lld_abort(SPIDriver *spip);
+#endif
+ uint32_t spi_lld_polled_exchange(SPIDriver *spip, uint32_t frame);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SPI */
+
+#endif /* HAL_SPI_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk new file mode 100644 index 0000000..032d75a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/driver.mk @@ -0,0 +1,19 @@ +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c
+
+ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_GPT TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c
+endif
+ifneq ($(findstring HAL_USE_ICU TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c
+endif
+ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c new file mode 100644 index 0000000..f7c449e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c @@ -0,0 +1,1153 @@ +/*
+ 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 TIMv1/hal_gpt_lld.c
+ * @brief STM32 GPT subsystem low level driver source.
+ *
+ * @addtogroup GPT
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_GPT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief GPTD1 driver identifier.
+ * @note The driver GPTD1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_GPT_USE_TIM1 || defined(__DOXYGEN__)
+GPTDriver GPTD1;
+#endif
+
+/**
+ * @brief GPTD2 driver identifier.
+ * @note The driver GPTD2 allocates the timer TIM2 when enabled.
+ */
+#if STM32_GPT_USE_TIM2 || defined(__DOXYGEN__)
+GPTDriver GPTD2;
+#endif
+
+/**
+ * @brief GPTD3 driver identifier.
+ * @note The driver GPTD3 allocates the timer TIM3 when enabled.
+ */
+#if STM32_GPT_USE_TIM3 || defined(__DOXYGEN__)
+GPTDriver GPTD3;
+#endif
+
+/**
+ * @brief GPTD4 driver identifier.
+ * @note The driver GPTD4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_GPT_USE_TIM4 || defined(__DOXYGEN__)
+GPTDriver GPTD4;
+#endif
+
+/**
+ * @brief GPTD5 driver identifier.
+ * @note The driver GPTD5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_GPT_USE_TIM5 || defined(__DOXYGEN__)
+GPTDriver GPTD5;
+#endif
+
+/**
+ * @brief GPTD6 driver identifier.
+ * @note The driver GPTD6 allocates the timer TIM6 when enabled.
+ */
+#if STM32_GPT_USE_TIM6 || defined(__DOXYGEN__)
+GPTDriver GPTD6;
+#endif
+
+/**
+ * @brief GPTD7 driver identifier.
+ * @note The driver GPTD7 allocates the timer TIM7 when enabled.
+ */
+#if STM32_GPT_USE_TIM7 || defined(__DOXYGEN__)
+GPTDriver GPTD7;
+#endif
+
+/**
+ * @brief GPTD8 driver identifier.
+ * @note The driver GPTD8 allocates the timer TIM8 when enabled.
+ */
+#if STM32_GPT_USE_TIM8 || defined(__DOXYGEN__)
+GPTDriver GPTD8;
+#endif
+
+/**
+ * @brief GPTD9 driver identifier.
+ * @note The driver GPTD9 allocates the timer TIM9 when enabled.
+ */
+#if STM32_GPT_USE_TIM9 || defined(__DOXYGEN__)
+GPTDriver GPTD9;
+#endif
+
+/**
+ * @brief GPTD10 driver identifier.
+ * @note The driver GPTD10 allocates the timer TIM10 when enabled.
+ */
+#if STM32_GPT_USE_TIM10 || defined(__DOXYGEN__)
+GPTDriver GPTD10;
+#endif
+
+/**
+ * @brief GPTD11 driver identifier.
+ * @note The driver GPTD11 allocates the timer TIM11 when enabled.
+ */
+#if STM32_GPT_USE_TIM11 || defined(__DOXYGEN__)
+GPTDriver GPTD11;
+#endif
+
+/**
+ * @brief GPTD12 driver identifier.
+ * @note The driver GPTD12 allocates the timer TIM12 when enabled.
+ */
+#if STM32_GPT_USE_TIM12 || defined(__DOXYGEN__)
+GPTDriver GPTD12;
+#endif
+
+/**
+ * @brief GPTD13 driver identifier.
+ * @note The driver GPTD13 allocates the timer TIM13 when enabled.
+ */
+#if STM32_GPT_USE_TIM13 || defined(__DOXYGEN__)
+GPTDriver GPTD13;
+#endif
+
+/**
+ * @brief GPTD14 driver identifier.
+ * @note The driver GPTD14 allocates the timer TIM14 when enabled.
+ */
+#if STM32_GPT_USE_TIM14 || defined(__DOXYGEN__)
+GPTDriver GPTD14;
+#endif
+
+/**
+ * @brief GPTD15 driver identifier.
+ * @note The driver GPTD14 allocates the timer TIM14 when enabled.
+ */
+#if STM32_GPT_USE_TIM15 || defined(__DOXYGEN__)
+GPTDriver GPTD15;
+#endif
+
+/**
+ * @brief GPTD16 driver identifier.
+ * @note The driver GPTD14 allocates the timer TIM14 when enabled.
+ */
+#if STM32_GPT_USE_TIM16 || defined(__DOXYGEN__)
+GPTDriver GPTD16;
+#endif
+
+/**
+ * @brief GPTD17 driver identifier.
+ * @note The driver GPTD14 allocates the timer TIM14 when enabled.
+ */
+#if STM32_GPT_USE_TIM17 || defined(__DOXYGEN__)
+GPTDriver GPTD17;
+#endif
+
+/**
+ * @brief GPTD21 driver identifier.
+ * @note The driver GPTD21 allocates the timer TIM21 when enabled.
+ */
+#if STM32_GPT_USE_TIM21 || defined(__DOXYGEN__)
+GPTDriver GPTD21;
+#endif
+
+/**
+ * @brief GPTD22 driver identifier.
+ * @note The driver GPTD22 allocates the timer TIM22 when enabled.
+ */
+#if STM32_GPT_USE_TIM22 || defined(__DOXYGEN__)
+GPTDriver GPTD22;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_GPT_USE_TIM1 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+#if !defined(STM32_TIM1_UP_HANDLER)
+#error "STM32_TIM1_UP_HANDLER not defined"
+#endif
+/**
+ * @brief TIM1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM1_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM1 */
+
+#if STM32_GPT_USE_TIM2 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+#if !defined(STM32_TIM2_HANDLER)
+#error "STM32_TIM2_HANDLER not defined"
+#endif
+/**
+ * @brief TIM2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM2_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM2 */
+
+#if STM32_GPT_USE_TIM3 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+#if !defined(STM32_TIM3_HANDLER)
+#error "STM32_TIM3_HANDLER not defined"
+#endif
+/**
+ * @brief TIM3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM3_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM3 */
+
+#if STM32_GPT_USE_TIM4 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+#if !defined(STM32_TIM4_HANDLER)
+#error "STM32_TIM4_HANDLER not defined"
+#endif
+/**
+ * @brief TIM4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM4_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM4 */
+
+#if STM32_GPT_USE_TIM5 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+#if !defined(STM32_TIM5_HANDLER)
+#error "STM32_TIM5_HANDLER not defined"
+#endif
+/**
+ * @brief TIM5 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM5_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM5 */
+
+#if STM32_GPT_USE_TIM6 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM6_SUPPRESS_ISR)
+#if !defined(STM32_TIM6_HANDLER)
+#error "STM32_TIM6_HANDLER not defined"
+#endif
+/**
+ * @brief TIM6 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM6_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM6 */
+
+#if STM32_GPT_USE_TIM7 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM7_SUPPRESS_ISR)
+#if !defined(STM32_TIM7_HANDLER)
+#error "STM32_TIM7_HANDLER not defined"
+#endif
+/**
+ * @brief TIM7 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM7_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM7 */
+
+#if STM32_GPT_USE_TIM8 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+#if !defined(STM32_TIM8_UP_HANDLER)
+#error "STM32_TIM8_UP_HANDLER not defined"
+#endif
+/**
+ * @brief TIM8 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM8_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM8 */
+
+#if STM32_GPT_USE_TIM9 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM9_SUPPRESS_ISR)
+#error "TIM9 ISR not defined by platform"
+#endif /* !defined(STM32_TIM9_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM9 */
+
+#if STM32_GPT_USE_TIM10 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM10_SUPPRESS_ISR)
+#error "TIM10 ISR not defined by platform"
+#endif /* !defined(STM32_TIM10_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM10 */
+
+#if STM32_GPT_USE_TIM11 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM11_SUPPRESS_ISR)
+#error "TIM11 ISR not defined by platform"
+#endif /* !defined(STM32_TIM11_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM11 */
+
+#if STM32_GPT_USE_TIM12 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM12_SUPPRESS_ISR)
+#error "TIM12 ISR not defined by platform"
+#endif /* !defined(STM32_TIM12_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM12 */
+
+#if STM32_GPT_USE_TIM13 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM13_SUPPRESS_ISR)
+#error "TIM13 ISR not defined by platform"
+#endif /* !defined(STM32_TIM13_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM13 */
+
+#if STM32_GPT_USE_TIM14 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM14_SUPPRESS_ISR)
+#error "TIM14 ISR not defined by platform"
+#endif /* !defined(STM32_TIM14_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM14 */
+
+#if STM32_GPT_USE_TIM15 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM15_SUPPRESS_ISR)
+#error "TIM15 ISR not defined by platform"
+#endif /* !defined(STM32_TIM15_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM15 */
+
+#if STM32_GPT_USE_TIM16 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM16_SUPPRESS_ISR)
+#error "TIM16 ISR not defined by platform"
+#endif /* !defined(STM32_TIM16_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM16 */
+
+#if STM32_GPT_USE_TIM17 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM17_SUPPRESS_ISR)
+#error "TIM17 ISR not defined by platform"
+#endif /* !defined(STM32_TIM17_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM17 */
+
+#if STM32_GPT_USE_TIM21 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM21_SUPPRESS_ISR)
+#if !defined(STM32_TIM21_HANDLER)
+#error "STM32_TIM21_HANDLER not defined"
+#endif
+/**
+ * @brief TIM21 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM21_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD21);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM21_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM21 */
+
+#if STM32_GPT_USE_TIM22 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM22_SUPPRESS_ISR)
+#if !defined(STM32_TIM22_HANDLER)
+#error "STM32_TIM22_HANDLER not defined"
+#endif
+/**
+ * @brief TIM22 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM22_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD22);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM22_SUPPRESS_ISR) */
+#endif /* STM32_GPT_USE_TIM22 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level GPT driver initialization.
+ *
+ * @notapi
+ */
+void gpt_lld_init(void) {
+
+#if STM32_GPT_USE_TIM1
+ /* Driver initialization.*/
+ GPTD1.tim = STM32_TIM1;
+ gptObjectInit(&GPTD1);
+#endif
+
+#if STM32_GPT_USE_TIM2
+ /* Driver initialization.*/
+ GPTD2.tim = STM32_TIM2;
+ gptObjectInit(&GPTD2);
+#endif
+
+#if STM32_GPT_USE_TIM3
+ /* Driver initialization.*/
+ GPTD3.tim = STM32_TIM3;
+ gptObjectInit(&GPTD3);
+#endif
+
+#if STM32_GPT_USE_TIM4
+ /* Driver initialization.*/
+ GPTD4.tim = STM32_TIM4;
+ gptObjectInit(&GPTD4);
+#endif
+
+#if STM32_GPT_USE_TIM5
+ /* Driver initialization.*/
+ GPTD5.tim = STM32_TIM5;
+ gptObjectInit(&GPTD5);
+#endif
+
+#if STM32_GPT_USE_TIM6
+ /* Driver initialization.*/
+ GPTD6.tim = STM32_TIM6;
+ gptObjectInit(&GPTD6);
+#endif
+
+#if STM32_GPT_USE_TIM7
+ /* Driver initialization.*/
+ GPTD7.tim = STM32_TIM7;
+ gptObjectInit(&GPTD7);
+#endif
+
+#if STM32_GPT_USE_TIM8
+ /* Driver initialization.*/
+ GPTD8.tim = STM32_TIM8;
+ gptObjectInit(&GPTD8);
+#endif
+
+#if STM32_GPT_USE_TIM9
+ /* Driver initialization.*/
+ GPTD9.tim = STM32_TIM9;
+ gptObjectInit(&GPTD9);
+#endif
+
+#if STM32_GPT_USE_TIM10
+ /* Driver initialization.*/
+ GPTD10.tim = STM32_TIM10;
+ gptObjectInit(&GPTD10);
+#endif
+
+#if STM32_GPT_USE_TIM11
+ /* Driver initialization.*/
+ GPTD11.tim = STM32_TIM11;
+ gptObjectInit(&GPTD11);
+#endif
+
+#if STM32_GPT_USE_TIM12
+ /* Driver initialization.*/
+ GPTD12.tim = STM32_TIM12;
+ gptObjectInit(&GPTD12);
+#endif
+
+#if STM32_GPT_USE_TIM13
+ /* Driver initialization.*/
+ GPTD13.tim = STM32_TIM13;
+ gptObjectInit(&GPTD13);
+#endif
+
+#if STM32_GPT_USE_TIM14
+ /* Driver initialization.*/
+ GPTD14.tim = STM32_TIM14;
+ gptObjectInit(&GPTD14);
+#endif
+
+#if STM32_GPT_USE_TIM15
+ /* Driver initialization.*/
+ GPTD15.tim = STM32_TIM15;
+ gptObjectInit(&GPTD15);
+#endif
+
+#if STM32_GPT_USE_TIM16
+ /* Driver initialization.*/
+ GPTD16.tim = STM32_TIM16;
+ gptObjectInit(&GPTD16);
+#endif
+
+#if STM32_GPT_USE_TIM17
+ /* Driver initialization.*/
+ GPTD17.tim = STM32_TIM17;
+ gptObjectInit(&GPTD17);
+#endif
+
+#if STM32_GPT_USE_TIM21
+ /* Driver initialization.*/
+ GPTD21.tim = STM32_TIM21;
+ gptObjectInit(&GPTD21);
+#endif
+
+#if STM32_GPT_USE_TIM22
+ /* Driver initialization.*/
+ GPTD22.tim = STM32_TIM22;
+ gptObjectInit(&GPTD22);
+#endif
+}
+
+/**
+ * @brief Configures and activates the GPT peripheral.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_start(GPTDriver *gptp) {
+ uint16_t psc;
+
+ if (gptp->state == GPT_STOP) {
+ /* Clock activation.*/
+#if STM32_GPT_USE_TIM1
+ if (&GPTD1 == gptp) {
+ rccEnableTIM1(true);
+ rccResetTIM1();
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_GPT_TIM1_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM1CLK)
+ gptp->clock = STM32_TIM1CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM2
+ if (&GPTD2 == gptp) {
+ rccEnableTIM2(true);
+ rccResetTIM2();
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM2_NUMBER, STM32_GPT_TIM2_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM2CLK)
+ gptp->clock = STM32_TIM2CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM3
+ if (&GPTD3 == gptp) {
+ rccEnableTIM3(true);
+ rccResetTIM3();
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM3_NUMBER, STM32_GPT_TIM3_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM3CLK)
+ gptp->clock = STM32_TIM3CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM4
+ if (&GPTD4 == gptp) {
+ rccEnableTIM4(true);
+ rccResetTIM4();
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM4_NUMBER, STM32_GPT_TIM4_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM4CLK)
+ gptp->clock = STM32_TIM4CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM5
+ if (&GPTD5 == gptp) {
+ rccEnableTIM5(true);
+ rccResetTIM5();
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM5_NUMBER, STM32_GPT_TIM5_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM5CLK)
+ gptp->clock = STM32_TIM5CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM6
+ if (&GPTD6 == gptp) {
+ rccEnableTIM6(true);
+ rccResetTIM6();
+#if !defined(STM32_TIM6_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM6_NUMBER, STM32_GPT_TIM6_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM6CLK)
+ gptp->clock = STM32_TIM6CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM7
+ if (&GPTD7 == gptp) {
+ rccEnableTIM7(true);
+ rccResetTIM7();
+#if !defined(STM32_TIM7_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM7_NUMBER, STM32_GPT_TIM7_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM7CLK)
+ gptp->clock = STM32_TIM7CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM8
+ if (&GPTD8 == gptp) {
+ rccEnableTIM8(true);
+ rccResetTIM8();
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_GPT_TIM8_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM8CLK)
+ gptp->clock = STM32_TIM8CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM9
+ if (&GPTD9 == gptp) {
+ rccEnableTIM9(true);
+ rccResetTIM9();
+#if !defined(STM32_TIM9_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM9_NUMBER, STM32_GPT_TIM9_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM9CLK)
+ gptp->clock = STM32_TIM9CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM10
+ if (&GPTD10 == gptp) {
+ rccEnableTIM10(true);
+ rccResetTIM10();
+#if !defined(STM32_TIM10_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM10_NUMBER, STM32_GPT_TIM10_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM10CLK)
+ gptp->clock = STM32_TIM10CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM11
+ if (&GPTD11 == gptp) {
+ rccEnableTIM11(true);
+ rccResetTIM11();
+#if !defined(STM32_TIM11_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM11_NUMBER, STM32_GPT_TIM11_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM11CLK)
+ gptp->clock = STM32_TIM11CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM12
+ if (&GPTD12 == gptp) {
+ rccEnableTIM12(true);
+ rccResetTIM12();
+#if !defined(STM32_TIM12_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM12_NUMBER, STM32_GPT_TIM12_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM12CLK)
+ gptp->clock = STM32_TIM12CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM13
+ if (&GPTD13 == gptp) {
+ rccEnableTIM13(true);
+ rccResetTIM13();
+#if !defined(STM32_TIM13_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM13_NUMBER, STM32_GPT_TIM13_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM13CLK)
+ gptp->clock = STM32_TIM13CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM14
+ if (&GPTD14 == gptp) {
+ rccEnableTIM14(true);
+ rccResetTIM14();
+#if !defined(STM32_TIM14_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM14_NUMBER, STM32_GPT_TIM14_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM14CLK)
+ gptp->clock = STM32_TIM14CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM15
+ if (&GPTD15 == gptp) {
+ rccEnableTIM15(true);
+ rccResetTIM15();
+#if defined(STM32_TIM15CLK)
+ gptp->clock = STM32_TIM15CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM16
+ if (&GPTD16 == gptp) {
+ rccEnableTIM16(true);
+ rccResetTIM16();
+#if defined(STM32_TIM16CLK)
+ gptp->clock = STM32_TIM16CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM17
+ if (&GPTD17 == gptp) {
+ rccEnableTIM17(true);
+ rccResetTIM17();
+#if defined(STM32_TIM17CLK)
+ gptp->clock = STM32_TIM17CLK;
+#else
+ gptp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM21
+ if (&GPTD21 == gptp) {
+ rccEnableTIM21(true);
+ rccResetTIM21();
+#if !defined(STM32_TIM21_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM21_NUMBER, STM32_GPT_TIM21_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM21CLK)
+ gptp->clock = STM32_TIM21CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_GPT_USE_TIM22
+ if (&GPTD22 == gptp) {
+ rccEnableTIM22(true);
+ rccResetTIM22();
+#if !defined(STM32_TIM22_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM22_NUMBER, STM32_GPT_TIM22_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM22CLK)
+ gptp->clock = STM32_TIM22CLK;
+#else
+ gptp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+ }
+
+ /* Prescaler value calculation.*/
+ psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1);
+ osalDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock,
+ "invalid frequency");
+
+ /* Timer configuration.*/
+ gptp->tim->CR1 = 0; /* Initially stopped. */
+ gptp->tim->CR2 = gptp->config->cr2;
+ gptp->tim->PSC = psc; /* Prescaler value. */
+ gptp->tim->SR = 0; /* Clear pending IRQs. */
+ gptp->tim->DIER = gptp->config->dier & /* DMA-related DIER bits. */
+ ~STM32_TIM_DIER_IRQ_MASK;
+}
+
+/**
+ * @brief Deactivates the GPT peripheral.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_stop(GPTDriver *gptp) {
+
+ if (gptp->state == GPT_READY) {
+ gptp->tim->CR1 = 0; /* Timer disabled. */
+ gptp->tim->DIER = 0; /* All IRQs disabled. */
+ gptp->tim->SR = 0; /* Clear pending IRQs. */
+
+#if STM32_GPT_USE_TIM1
+ if (&GPTD1 == gptp) {
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM1_UP_NUMBER);
+#endif
+ rccDisableTIM1();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM2
+ if (&GPTD2 == gptp) {
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM2_NUMBER);
+#endif
+ rccDisableTIM2();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM3
+ if (&GPTD3 == gptp) {
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM3_NUMBER);
+#endif
+ rccDisableTIM3();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM4
+ if (&GPTD4 == gptp) {
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM4_NUMBER);
+#endif
+ rccDisableTIM4();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM5
+ if (&GPTD5 == gptp) {
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM5_NUMBER);
+#endif
+ rccDisableTIM5();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM6
+ if (&GPTD6 == gptp) {
+#if !defined(STM32_TIM6_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM6_NUMBER);
+#endif
+ rccDisableTIM6();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM7
+ if (&GPTD7 == gptp) {
+#if !defined(STM32_TIM7_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM7_NUMBER);
+#endif
+ rccDisableTIM7();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM8
+ if (&GPTD8 == gptp) {
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM8_UP_NUMBER);
+#endif
+ rccDisableTIM8();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM9
+ if (&GPTD9 == gptp) {
+#if !defined(STM32_TIM9_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM9_NUMBER);
+#endif
+ rccDisableTIM9();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM10
+ if (&GPTD10 == gptp) {
+#if !defined(STM32_TIM10_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM10_NUMBER);
+#endif
+ rccDisableTIM10();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM11
+ if (&GPTD11 == gptp) {
+#if !defined(STM32_TIM11_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM11_NUMBER);
+#endif
+ rccDisableTIM11();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM12
+ if (&GPTD12 == gptp) {
+#if !defined(STM32_TIM12_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM12_NUMBER);
+#endif
+ rccDisableTIM12();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM13
+ if (&GPTD13 == gptp) {
+#if !defined(STM32_TIM13_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM13_NUMBER);
+#endif
+ rccDisableTIM13();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM14
+ if (&GPTD14 == gptp) {
+#if !defined(STM32_TIM14_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM14_NUMBER);
+#endif
+ rccDisableTIM14();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM15
+ if (&GPTD15 == gptp) {
+ rccDisableTIM15();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM16
+ if (&GPTD16 == gptp) {
+ rccDisableTIM16();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM17
+ if (&GPTD17 == gptp) {
+ rccDisableTIM17();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM21
+ if (&GPTD21 == gptp) {
+#if !defined(STM32_TIM21_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM21_NUMBER);
+#endif
+ rccDisableTIM21();
+ }
+#endif
+
+#if STM32_GPT_USE_TIM22
+ if (&GPTD22 == gptp) {
+#if !defined(STM32_TIM22_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM22_NUMBER);
+#endif
+ rccDisableTIM22();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts the timer in continuous mode.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ * @param[in] interval period in ticks
+ *
+ * @notapi
+ */
+void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
+
+ gptp->tim->ARR = (uint32_t)(interval - 1U); /* Time constant. */
+ gptp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
+ gptp->tim->CNT = 0; /* Reset counter. */
+
+ /* NOTE: After generating the UG event it takes several clock cycles before
+ SR bit 0 goes to 1. This is why the clearing of CNT has been inserted
+ before the clearing of SR, to give it some time.*/
+ gptp->tim->SR = 0; /* Clear pending IRQs. */
+ if (NULL != gptp->config->callback)
+ gptp->tim->DIER |= STM32_TIM_DIER_UIE; /* Update Event IRQ enabled.*/
+ gptp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
+}
+
+/**
+ * @brief Stops the timer.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_stop_timer(GPTDriver *gptp) {
+
+ gptp->tim->CR1 = 0; /* Initially stopped. */
+ gptp->tim->SR = 0; /* Clear pending IRQs. */
+
+ /* All interrupts disabled.*/
+ gptp->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK;
+}
+
+/**
+ * @brief Starts the timer in one shot mode and waits for completion.
+ * @details This function specifically polls the timer waiting for completion
+ * in order to not have extra delays caused by interrupt servicing,
+ * this function is only recommended for short delays.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ * @param[in] interval time interval in ticks
+ *
+ * @notapi
+ */
+void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
+
+ gptp->tim->ARR = (uint32_t)(interval - 1U); /* Time constant. */
+ gptp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
+ gptp->tim->SR = 0; /* Clear pending IRQs. */
+ gptp->tim->CR1 = STM32_TIM_CR1_OPM | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
+ while (!(gptp->tim->SR & STM32_TIM_SR_UIF))
+ ;
+ gptp->tim->SR = 0; /* Clear pending IRQs. */
+}
+
+/**
+ * @brief Shared IRQ handler.
+ *
+ * @param[in] gptp pointer to a @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_serve_interrupt(GPTDriver *gptp) {
+ uint32_t sr;
+
+ sr = gptp->tim->SR;
+ sr &= gptp->tim->DIER & STM32_TIM_DIER_IRQ_MASK;
+ gptp->tim->SR = ~sr;
+ if ((sr & STM32_TIM_SR_UIF) != 0) {
+ _gpt_isr_invoke_cb(gptp);
+ }
+}
+
+#endif /* HAL_USE_GPT */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h new file mode 100644 index 0000000..1fbdea3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.h @@ -0,0 +1,980 @@ +/*
+ 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 TIMv1/hal_gpt_lld.h
+ * @brief STM32 GPT subsystem low level driver header.
+ *
+ * @addtogroup GPT
+ * @{
+ */
+
+#ifndef HAL_GPT_LLD_H
+#define HAL_GPT_LLD_H
+
+#include "stm32_tim.h"
+
+#if HAL_USE_GPT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief GPTD1 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM1 FALSE
+#endif
+
+/**
+ * @brief GPTD2 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM2 FALSE
+#endif
+
+/**
+ * @brief GPTD3 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM3 FALSE
+#endif
+
+/**
+ * @brief GPTD4 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM4 FALSE
+#endif
+
+/**
+ * @brief GPTD5 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM5 FALSE
+#endif
+
+/**
+ * @brief GPTD6 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM6) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM6 FALSE
+#endif
+
+/**
+ * @brief GPTD7 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD7 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM7) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM7 FALSE
+#endif
+
+/**
+ * @brief GPTD8 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM8) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM8 FALSE
+#endif
+
+/**
+ * @brief GPTD9 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD9 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM9) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM9 FALSE
+#endif
+
+/**
+ * @brief GPTD10 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD10 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM10) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM10 FALSE
+#endif
+
+/**
+ * @brief GPTD11 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD11 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM11) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM11 FALSE
+#endif
+
+/**
+ * @brief GPTD12 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD12 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM12) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM12 FALSE
+#endif
+
+/**
+ * @brief GPTD13 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD13 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM13) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM13 FALSE
+#endif
+
+/**
+ * @brief GPTD14 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD14 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM14) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM14 FALSE
+#endif
+
+/**
+ * @brief GPTD14 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD15 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM15) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM15 FALSE
+#endif
+
+/**
+ * @brief GPTD14 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD16 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM16) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM16 FALSE
+#endif
+
+/**
+ * @brief GPTD14 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD17 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM17) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM17 FALSE
+#endif
+
+/**
+ * @brief GPTD21 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD21 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM21) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM21 FALSE
+#endif
+
+/**
+ * @brief GPTD22 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD22 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_GPT_USE_TIM22) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM22 FALSE
+#endif
+
+/**
+ * @brief GPTD1 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM1_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD2 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM2_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD3 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM3_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD4 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM4_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD5 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM5_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD6 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM6_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM6_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD7 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM7_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM7_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD8 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM8_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD9 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM9_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD10 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM10_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD11 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM11_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD12 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM12_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD13 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM13_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD14 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM14_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD15 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM15_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM15_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD16 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM16_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM16_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD17 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM17_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM17_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD21 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM21_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM21_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD22 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM22_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM22_IRQ_PRIORITY 7
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_TIM1)
+#define STM32_HAS_TIM1 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM2)
+#define STM32_HAS_TIM2 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM3)
+#define STM32_HAS_TIM3 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM4)
+#define STM32_HAS_TIM4 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM5)
+#define STM32_HAS_TIM5 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM6)
+#define STM32_HAS_TIM6 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM7)
+#define STM32_HAS_TIM7 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM8)
+#define STM32_HAS_TIM8 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM9)
+#define STM32_HAS_TIM9 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM10)
+#define STM32_HAS_TIM10 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM11)
+#define STM32_HAS_TIM11 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM12)
+#define STM32_HAS_TIM12 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM13)
+#define STM32_HAS_TIM13 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM14)
+#define STM32_HAS_TIM14 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM15)
+#define STM32_HAS_TIM15 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM16)
+#define STM32_HAS_TIM16 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM17)
+#define STM32_HAS_TIM17 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM21)
+#define STM32_HAS_TIM21 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM22)
+#define STM32_HAS_TIM22 FALSE
+#endif
+
+#if STM32_GPT_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM6 && !STM32_HAS_TIM6
+#error "TIM6 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM7 && !STM32_HAS_TIM7
+#error "TIM7 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM8 && !STM32_HAS_TIM8
+#error "TIM8 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM9 && !STM32_HAS_TIM9
+#error "TIM9 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM10 && !STM32_HAS_TIM10
+#error "TIM10 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM11 && !STM32_HAS_TIM11
+#error "TIM11 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM12 && !STM32_HAS_TIM12
+#error "TIM12 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM13 && !STM32_HAS_TIM13
+#error "TIM13 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM14 && !STM32_HAS_TIM14
+#error "TIM14 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM15 && !STM32_HAS_TIM15
+#error "TIM15 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM16 && !STM32_HAS_TIM16
+#error "TIM16 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM17 && !STM32_HAS_TIM17
+#error "TIM17 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM21 && !STM32_HAS_TIM21
+#error "TIM21 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM22 && !STM32_HAS_TIM22
+#error "TIM22 not present in the selected device"
+#endif
+
+#if !STM32_GPT_USE_TIM1 && !STM32_GPT_USE_TIM2 && \
+ !STM32_GPT_USE_TIM3 && !STM32_GPT_USE_TIM4 && \
+ !STM32_GPT_USE_TIM5 && !STM32_GPT_USE_TIM6 && \
+ !STM32_GPT_USE_TIM7 && !STM32_GPT_USE_TIM8 && \
+ !STM32_GPT_USE_TIM9 && !STM32_GPT_USE_TIM10 && \
+ !STM32_GPT_USE_TIM11 && !STM32_GPT_USE_TIM12 && \
+ !STM32_GPT_USE_TIM13 && !STM32_GPT_USE_TIM14 && \
+ !STM32_GPT_USE_TIM15 && !STM32_GPT_USE_TIM16 && \
+ !STM32_GPT_USE_TIM17 && \
+ !STM32_GPT_USE_TIM21 && !STM32_GPT_USE_TIM22
+#error "GPT driver activated but no TIM peripheral assigned"
+#endif
+
+/* Checks on allocation of TIMx units.*/
+#if STM32_GPT_USE_TIM1
+#if defined(STM32_TIM1_IS_USED)
+#error "GPTD1 requires TIM1 but the timer is already used"
+#else
+#define STM32_TIM1_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM2
+#if defined(STM32_TIM2_IS_USED)
+#error "GPTD2 requires TIM2 but the timer is already used"
+#else
+#define STM32_TIM2_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM3
+#if defined(STM32_TIM3_IS_USED)
+#error "GPTD3 requires TIM3 but the timer is already used"
+#else
+#define STM32_TIM3_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM4
+#if defined(STM32_TIM4_IS_USED)
+#error "GPTD4 requires TIM4 but the timer is already used"
+#else
+#define STM32_TIM4_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM5
+#if defined(STM32_TIM5_IS_USED)
+#error "GPTD5 requires TIM5 but the timer is already used"
+#else
+#define STM32_TIM5_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM6
+#if defined(STM32_TIM6_IS_USED)
+#error "GPTD6 requires TIM6 but the timer is already used"
+#else
+#define STM32_TIM6_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM7
+#if defined(STM32_TIM7_IS_USED)
+#error "GPTD7 requires TIM7 but the timer is already used"
+#else
+#define STM32_TIM7_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM8
+#if defined(STM32_TIM8_IS_USED)
+#error "GPTD8 requires TIM8 but the timer is already used"
+#else
+#define STM32_TIM8_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM9
+#if defined(STM32_TIM9_IS_USED)
+#error "GPTD9 requires TIM9 but the timer is already used"
+#else
+#define STM32_TIM9_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM10
+#if defined(STM32_TIM10_IS_USED)
+#error "GPTD10 requires TIM10 but the timer is already used"
+#else
+#define STM32_TIM10_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM11
+#if defined(STM32_TIM11_IS_USED)
+#error "GPTD11 requires TIM11 but the timer is already used"
+#else
+#define STM32_TIM11_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM12
+#if defined(STM32_TIM12_IS_USED)
+#error "GPTD12 requires TIM12 but the timer is already used"
+#else
+#define STM32_TIM12_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM13
+#if defined(STM32_TIM13_IS_USED)
+#error "GPTD13 requires TIM13 but the timer is already used"
+#else
+#define STM32_TIM13_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM14
+#if defined(STM32_TIM14_IS_USED)
+#error "GPTD14 requires TIM14 but the timer is already used"
+#else
+#define STM32_TIM14_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM15
+#if defined(STM32_TIM15_IS_USED)
+#error "GPTD14 requires TIM15 but the timer is already used"
+#else
+#define STM32_TIM15_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM16
+#if defined(STM32_TIM16_IS_USED)
+#error "GPTD14 requires TIM16 but the timer is already used"
+#else
+#define STM32_TIM16_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM17
+#if defined(STM32_TIM17_IS_USED)
+#error "GPTD14 requires TIM17 but the timer is already used"
+#else
+#define STM32_TIM17_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM21
+#if defined(STM32_TIM21_IS_USED)
+#error "GPTD21 requires TIM21 but the timer is already used"
+#else
+#define STM32_TIM21_IS_USED
+#endif
+#endif
+
+#if STM32_GPT_USE_TIM22
+#if defined(STM32_TIM22_IS_USED)
+#error "GPTD22 requires TIM22 but the timer is already used"
+#else
+#define STM32_TIM22_IS_USED
+#endif
+#endif
+
+/* IRQ priority checks.*/
+#if STM32_GPT_USE_TIM1 && !defined(STM32_TIM1_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM1"
+#endif
+
+#if STM32_GPT_USE_TIM2 && !defined(STM32_TIM2_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM2"
+#endif
+
+#if STM32_GPT_USE_TIM3 && !defined(STM32_TIM3_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM3"
+#endif
+
+#if STM32_GPT_USE_TIM4 && !defined(STM32_TIM_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM4"
+#endif
+
+#if STM32_GPT_USE_TIM5 && !defined(STM32_TIM5_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM5"
+#endif
+
+#if STM32_GPT_USE_TIM6 && !defined(STM32_TIM6_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM6_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM6"
+#endif
+
+#if STM32_GPT_USE_TIM7 && !defined(STM32_TIM7_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM7_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM7"
+#endif
+
+#if STM32_GPT_USE_TIM8 && !defined(STM32_TIM8_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM8_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM8"
+#endif
+
+#if STM32_GPT_USE_TIM9 && !defined(STM32_TIM9_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM9_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM9"
+#endif
+
+#if STM32_GPT_USE_TIM10 && !defined(STM32_TIM10_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM10_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM10"
+#endif
+
+#if STM32_GPT_USE_TIM11 && !defined(STM32_TIM11_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM11_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM11"
+#endif
+
+#if STM32_GPT_USE_TIM12 && !defined(STM32_TIM12_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM12_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM12"
+#endif
+
+#if STM32_GPT_USE_TIM13 && !defined(STM32_TIM13_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM13_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM13"
+#endif
+
+#if STM32_GPT_USE_TIM14 && !defined(STM32_TIM14_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM14_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM14"
+#endif
+
+#if STM32_GPT_USE_TIM15 && !defined(STM32_TIM15_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM15_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM15"
+#endif
+
+#if STM32_GPT_USE_TIM16 && !defined(STM32_TIM16_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM16_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM16"
+#endif
+
+#if STM32_GPT_USE_TIM17 && !defined(STM32_TIM17_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM17_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM17"
+#endif
+
+#if STM32_GPT_USE_TIM21 && !defined(STM32_TIM21_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM21_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM21"
+#endif
+
+#if STM32_GPT_USE_TIM22 && !defined(STM32_TIM22_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_GPT_TIM22_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM22"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief GPT frequency type.
+ */
+typedef uint32_t gptfreq_t;
+
+/**
+ * @brief GPT counter type.
+ */
+typedef uint32_t gptcnt_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ gptfreq_t frequency;
+ /**
+ * @brief Timer callback pointer.
+ * @note This callback is invoked on GPT counter events.
+ * @note This callback can be set to @p NULL but in that case the
+ * one-shot mode cannot be used.
+ */
+ gptcallback_t callback;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief TIM CR2 register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ */
+ uint32_t cr2;
+ /**
+ * @brief TIM DIER register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ * @note Only the DMA-related bits can be specified in this field.
+ */
+ uint32_t dier;
+} GPTConfig;
+
+/**
+ * @brief Structure representing a GPT driver.
+ */
+struct GPTDriver {
+ /**
+ * @brief Driver state.
+ */
+ gptstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const GPTConfig *config;
+#if defined(GPT_DRIVER_EXT_FIELDS)
+ GPT_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
+ * @brief Pointer to the TIMx registers block.
+ */
+ stm32_tim_t *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Changes the interval of GPT peripheral.
+ * @details This function changes the interval of a running GPT unit.
+ * @pre The GPT unit must be running in continuous mode.
+ * @post The GPT unit interval is changed to the new value.
+ * @note The function has effect at the next cycle start.
+ *
+ * @param[in] gptp pointer to a @p GPTDriver object
+ * @param[in] interval new cycle time in timer ticks
+ *
+ * @notapi
+ */
+#define gpt_lld_change_interval(gptp, interval) \
+ ((gptp)->tim->ARR = (uint32_t)((interval) - 1U))
+
+/**
+ * @brief Returns the interval of GPT peripheral.
+ * @pre The GPT unit must be running in continuous mode.
+ *
+ * @param[in] gptp pointer to a @p GPTDriver object
+ * @return The current interval.
+ *
+ * @notapi
+ */
+#define gpt_lld_get_interval(gptp) ((gptcnt_t)((gptp)->tim->ARR + 1U))
+
+/**
+ * @brief Returns the counter value of GPT peripheral.
+ * @pre The GPT unit must be running in continuous mode.
+ * @note The nature of the counter is not defined, it may count upward
+ * or downward, it could be continuously running or not.
+ *
+ * @param[in] gptp pointer to a @p GPTDriver object
+ * @return The current counter value.
+ *
+ * @notapi
+ */
+#define gpt_lld_get_counter(gptp) ((gptcnt_t)(gptp)->tim->CNT)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_GPT_USE_TIM1 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD1;
+#endif
+
+#if STM32_GPT_USE_TIM2 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD2;
+#endif
+
+#if STM32_GPT_USE_TIM3 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD3;
+#endif
+
+#if STM32_GPT_USE_TIM4 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD4;
+#endif
+
+#if STM32_GPT_USE_TIM5 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD5;
+#endif
+
+#if STM32_GPT_USE_TIM6 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD6;
+#endif
+
+#if STM32_GPT_USE_TIM7 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD7;
+#endif
+
+#if STM32_GPT_USE_TIM8 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD8;
+#endif
+
+#if STM32_GPT_USE_TIM9 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD9;
+#endif
+
+#if STM32_GPT_USE_TIM10 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD10;
+#endif
+
+#if STM32_GPT_USE_TIM11 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD11;
+#endif
+
+#if STM32_GPT_USE_TIM12 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD12;
+#endif
+
+#if STM32_GPT_USE_TIM13 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD13;
+#endif
+
+#if STM32_GPT_USE_TIM14 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD14;
+#endif
+
+#if STM32_GPT_USE_TIM15 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD15;
+#endif
+
+#if STM32_GPT_USE_TIM16 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD16;
+#endif
+
+#if STM32_GPT_USE_TIM17 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD17;
+#endif
+
+#if STM32_GPT_USE_TIM21 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD21;
+#endif
+
+#if STM32_GPT_USE_TIM22 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD22;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void gpt_lld_init(void);
+ void gpt_lld_start(GPTDriver *gptp);
+ void gpt_lld_stop(GPTDriver *gptp);
+ void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
+ void gpt_lld_stop_timer(GPTDriver *gptp);
+ void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
+ void gpt_lld_serve_interrupt(GPTDriver *gptp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_GPT */
+
+#endif /* HAL_GPT_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c new file mode 100644 index 0000000..e9a669d --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c @@ -0,0 +1,1135 @@ +/*
+ 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.
+*/
+/*
+ Concepts and parts of this file have been contributed by Fabio Utzig and
+ Xo Wang.
+ */
+
+/**
+ * @file TIMv1/hal_icu_lld.c
+ * @brief STM32 ICU subsystem low level driver header.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief ICUD1 driver identifier.
+ * @note The driver ICUD1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__)
+ICUDriver ICUD1;
+#endif
+
+/**
+ * @brief ICUD2 driver identifier.
+ * @note The driver ICUD1 allocates the timer TIM2 when enabled.
+ */
+#if STM32_ICU_USE_TIM2 || defined(__DOXYGEN__)
+ICUDriver ICUD2;
+#endif
+
+/**
+ * @brief ICUD3 driver identifier.
+ * @note The driver ICUD1 allocates the timer TIM3 when enabled.
+ */
+#if STM32_ICU_USE_TIM3 || defined(__DOXYGEN__)
+ICUDriver ICUD3;
+#endif
+
+/**
+ * @brief ICUD4 driver identifier.
+ * @note The driver ICUD4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_ICU_USE_TIM4 || defined(__DOXYGEN__)
+ICUDriver ICUD4;
+#endif
+
+/**
+ * @brief ICUD5 driver identifier.
+ * @note The driver ICUD5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_ICU_USE_TIM5 || defined(__DOXYGEN__)
+ICUDriver ICUD5;
+#endif
+
+/**
+ * @brief ICUD8 driver identifier.
+ * @note The driver ICUD8 allocates the timer TIM8 when enabled.
+ */
+#if STM32_ICU_USE_TIM8 || defined(__DOXYGEN__)
+ICUDriver ICUD8;
+#endif
+
+/**
+ * @brief ICUD9 driver identifier.
+ * @note The driver ICUD9 allocates the timer TIM9 when enabled.
+ */
+#if STM32_ICU_USE_TIM9 || defined(__DOXYGEN__)
+ICUDriver ICUD9;
+#endif
+
+/**
+ * @brief ICUD10 driver identifier.
+ * @note The driver ICUD10 allocates the timer TIM10 when enabled.
+ */
+#if STM32_ICU_USE_TIM10 || defined(__DOXYGEN__)
+ICUDriver ICUD10;
+#endif
+
+/**
+ * @brief ICUD11 driver identifier.
+ * @note The driver ICUD11 allocates the timer TIM11 when enabled.
+ */
+#if STM32_ICU_USE_TIM11 || defined(__DOXYGEN__)
+ICUDriver ICUD11;
+#endif
+
+/**
+ * @brief ICUD12 driver identifier.
+ * @note The driver ICUD12 allocates the timer TIM12 when enabled.
+ */
+#if STM32_ICU_USE_TIM12 || defined(__DOXYGEN__)
+ICUDriver ICUD12;
+#endif
+
+/**
+ * @brief ICUD13 driver identifier.
+ * @note The driver ICUD13 allocates the timer TIM13 when enabled.
+ */
+#if STM32_ICU_USE_TIM13 || defined(__DOXYGEN__)
+ICUDriver ICUD13;
+#endif
+
+/**
+ * @brief ICUD14 driver identifier.
+ * @note The driver ICUD14 allocates the timer TIM14 when enabled.
+ */
+#if STM32_ICU_USE_TIM14 || defined(__DOXYGEN__)
+ICUDriver ICUD14;
+#endif
+
+/**
+ * @brief ICUD15 driver identifier.
+ * @note The driver ICUD15 allocates the timer TIM15 when enabled.
+ */
+#if STM32_ICU_USE_TIM15 || defined(__DOXYGEN__)
+ICUDriver ICUD15;
+#endif
+
+/**
+ * @brief ICUD20 driver identifier.
+ * @note The driver ICUD20 allocates the timer TIM20 when enabled.
+ */
+#if STM32_ICU_USE_TIM20 || defined(__DOXYGEN__)
+ICUDriver ICUD20;
+#endif
+
+/**
+ * @brief ICUD21 driver identifier.
+ * @note The driver ICUD21 allocates the timer TIM21 when enabled.
+ */
+#if STM32_ICU_USE_TIM21 || defined(__DOXYGEN__)
+ICUDriver ICUD21;
+#endif
+
+/**
+ * @brief ICUD22 driver identifier.
+ * @note The driver ICUD22 allocates the timer TIM22 when enabled.
+ */
+#if STM32_ICU_USE_TIM22 || defined(__DOXYGEN__)
+ICUDriver ICUD22;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static bool icu_lld_wait_edge(ICUDriver *icup) {
+ uint32_t sr;
+ bool result;
+
+ /* Polled mode so re-enabling the interrupts while the operation is
+ performed.*/
+ osalSysUnlock();
+
+ /* Polling the right bit depending on the input channel.*/
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ /* Waiting for an edge.*/
+ while (((sr = icup->tim->SR) &
+ (STM32_TIM_SR_CC1IF | STM32_TIM_SR_UIF)) == 0)
+ ;
+ }
+ else {
+ /* Waiting for an edge.*/
+ while (((sr = icup->tim->SR) &
+ (STM32_TIM_SR_CC2IF | STM32_TIM_SR_UIF)) == 0)
+ ;
+ }
+
+ /* Edge or overflow?*/
+ result = (sr & STM32_TIM_SR_UIF) != 0 ? true : false;
+
+ /* Done, disabling interrupts again.*/
+ osalSysLock();
+
+ /* Resetting all flags.*/
+ icup->tim->SR &= ~(STM32_TIM_SR_CC1IF |
+ STM32_TIM_SR_CC2IF |
+ STM32_TIM_SR_UIF);
+
+ return result;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+#if !defined(STM32_TIM1_UP_HANDLER)
+#error "STM32_TIM1_UP_HANDLER not defined"
+#endif
+/**
+ * @brief TIM1 compare interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(STM32_TIM1_CC_HANDLER)
+#error "STM32_TIM1_CC_HANDLER not defined"
+#endif
+/**
+ * @brief TIM1 compare interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM1_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM1 */
+
+#if STM32_ICU_USE_TIM2 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+#if !defined(STM32_TIM2_HANDLER)
+#error "STM32_TIM2_HANDLER not defined"
+#endif
+/**
+ * @brief TIM2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM2_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM2 */
+
+#if STM32_ICU_USE_TIM3 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+#if !defined(STM32_TIM3_HANDLER)
+#error "STM32_TIM3_HANDLER not defined"
+#endif
+/**
+ * @brief TIM3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM3_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM3 */
+
+#if STM32_ICU_USE_TIM4 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+#if !defined(STM32_TIM4_HANDLER)
+#error "STM32_TIM4_HANDLER not defined"
+#endif
+/**
+ * @brief TIM4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM4_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM4 */
+
+#if STM32_ICU_USE_TIM5 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+#if !defined(STM32_TIM5_HANDLER)
+#error "STM32_TIM5_HANDLER not defined"
+#endif
+/**
+ * @brief TIM5 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM5_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM5 */
+
+#if STM32_ICU_USE_TIM8 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+#if !defined(STM32_TIM8_UP_HANDLER)
+#error "STM32_TIM8_UP_HANDLER not defined"
+#endif
+/**
+ * @brief TIM8 compare interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(STM32_TIM8_CC_HANDLER)
+#error "STM32_TIM8_CC_HANDLER not defined"
+#endif
+/**
+ * @brief TIM8 compare interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM8_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM8 */
+
+#if STM32_ICU_USE_TIM9 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM9_SUPPRESS_ISR)
+#error "TIM9 ISR not defined by platform"
+#endif /* !defined(STM32_TIM9_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM9 */
+
+#if STM32_ICU_USE_TIM10 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM10_SUPPRESS_ISR)
+#error "TIM10 ISR not defined by platform"
+#endif /* !defined(STM32_TIM10_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM10 */
+
+#if STM32_ICU_USE_TIM11 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM11_SUPPRESS_ISR)
+#error "TIM11 ISR not defined by platform"
+#endif /* !defined(STM32_TIM11_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM11 */
+
+#if STM32_ICU_USE_TIM12 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM12_SUPPRESS_ISR)
+#error "TIM12 ISR not defined by platform"
+#endif /* !defined(STM32_TIM12_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM12 */
+
+#if STM32_ICU_USE_TIM13 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM13_SUPPRESS_ISR)
+#error "TIM13 ISR not defined by platform"
+#endif /* !defined(STM32_TIM13_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM13 */
+
+#if STM32_ICU_USE_TIM14 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM14_SUPPRESS_ISR)
+#error "TIM14 ISR not defined by platform"
+#endif /* !defined(STM32_TIM14_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM14 */
+
+#if STM32_ICU_USE_TIM15 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM15_SUPPRESS_ISR)
+#error "TIM15 ISR not defined by platform"
+#endif /* !defined(STM32_TIM15_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM15 */
+
+#if STM32_ICU_USE_TIM20 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM20_SUPPRESS_ISR)
+#error "TIM20 ISR not defined by platform"
+#endif /* !defined(STM32_TIM20_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM20 */
+
+#if STM32_ICU_USE_TIM21 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM21_SUPPRESS_ISR)
+#error "TIM21 ISR not defined by platform"
+#endif /* !defined(STM32_TIM21_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM21 */
+
+#if STM32_ICU_USE_TIM22 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM22_SUPPRESS_ISR)
+#error "TIM22 ISR not defined by platform"
+#endif /* !defined(STM32_TIM22_SUPPRESS_ISR) */
+#endif /* STM32_ICU_USE_TIM22 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ICU driver initialization.
+ *
+ * @notapi
+ */
+void icu_lld_init(void) {
+
+#if STM32_ICU_USE_TIM1
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD1);
+ ICUD1.tim = STM32_TIM1;
+#endif
+
+#if STM32_ICU_USE_TIM2
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD2);
+ ICUD2.tim = STM32_TIM2;
+#endif
+
+#if STM32_ICU_USE_TIM3
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD3);
+ ICUD3.tim = STM32_TIM3;
+#endif
+
+#if STM32_ICU_USE_TIM4
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD4);
+ ICUD4.tim = STM32_TIM4;
+#endif
+
+#if STM32_ICU_USE_TIM5
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD5);
+ ICUD5.tim = STM32_TIM5;
+#endif
+
+#if STM32_ICU_USE_TIM8
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD8);
+ ICUD8.tim = STM32_TIM8;
+#endif
+
+#if STM32_ICU_USE_TIM9
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD9);
+ ICUD9.tim = STM32_TIM9;
+#endif
+
+#if STM32_ICU_USE_TIM10
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD10);
+ ICUD10.tim = STM32_TIM10;
+#endif
+
+#if STM32_ICU_USE_TIM11
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD11);
+ ICUD11.tim = STM32_TIM11;
+#endif
+
+#if STM32_ICU_USE_TIM12
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD12);
+ ICUD12.tim = STM32_TIM12;
+#endif
+
+#if STM32_ICU_USE_TIM13
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD13);
+ ICUD13.tim = STM32_TIM13;
+#endif
+
+#if STM32_ICU_USE_TIM14
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD14);
+ ICUD14.tim = STM32_TIM14;
+#endif
+
+#if STM32_ICU_USE_TIM15
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD15);
+ ICUD15.tim = STM32_TIM15;
+#endif
+
+#if STM32_ICU_USE_TIM20
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD20);
+ ICUD20.tim = STM32_TIM20;
+#endif
+
+#if STM32_ICU_USE_TIM21
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD21);
+ ICUD21.tim = STM32_TIM21;
+#endif
+
+#if STM32_ICU_USE_TIM22
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD22);
+ ICUD22.tim = STM32_TIM22;
+#endif
+}
+
+/**
+ * @brief Configures and activates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_start(ICUDriver *icup) {
+ uint32_t psc;
+
+ osalDbgAssert((icup->config->channel == ICU_CHANNEL_1) ||
+ (icup->config->channel == ICU_CHANNEL_2),
+ "invalid input");
+
+ if (icup->state == ICU_STOP) {
+ /* Clock activation and timer reset.*/
+#if STM32_ICU_USE_TIM1
+ if (&ICUD1 == icup) {
+ rccEnableTIM1(true);
+ rccResetTIM1();
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_ICU_TIM1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_ICU_TIM1_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM1CLK)
+ icup->clock = STM32_TIM1CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM2
+ if (&ICUD2 == icup) {
+ rccEnableTIM2(true);
+ rccResetTIM2();
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM2_NUMBER, STM32_ICU_TIM2_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM2CLK)
+ icup->clock = STM32_TIM2CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM3
+ if (&ICUD3 == icup) {
+ rccEnableTIM3(true);
+ rccResetTIM3();
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM3_NUMBER, STM32_ICU_TIM3_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM3CLK)
+ icup->clock = STM32_TIM3CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM4
+ if (&ICUD4 == icup) {
+ rccEnableTIM4(true);
+ rccResetTIM4();
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM4_NUMBER, STM32_ICU_TIM4_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM4CLK)
+ icup->clock = STM32_TIM4CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM5
+ if (&ICUD5 == icup) {
+ rccEnableTIM5(true);
+ rccResetTIM5();
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM5_NUMBER, STM32_ICU_TIM5_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM5CLK)
+ icup->clock = STM32_TIM5CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM8
+ if (&ICUD8 == icup) {
+ rccEnableTIM8(true);
+ rccResetTIM8();
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_ICU_TIM8_IRQ_PRIORITY);
+ nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_ICU_TIM8_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM8CLK)
+ icup->clock = STM32_TIM8CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM9
+ if (&ICUD9 == icup) {
+ rccEnableTIM9(true);
+ rccResetTIM9();
+#if defined(STM32_TIM9CLK)
+ icup->clock = STM32_TIM9CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM10
+ if (&ICUD10 == icup) {
+ rccEnableTIM10(true);
+ rccResetTIM10();
+#if defined(STM32_TIM10CLK)
+ icup->clock = STM32_TIM10CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM11
+ if (&ICUD11 == icup) {
+ rccEnableTIM11(true);
+ rccResetTIM11();
+#if defined(STM32_TIM11CLK)
+ icup->clock = STM32_TIM11CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM12
+ if (&ICUD12 == icup) {
+ rccEnableTIM12(true);
+ rccResetTIM12();
+#if defined(STM32_TIM12CLK)
+ icup->clock = STM32_TIM12CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM13
+ if (&ICUD13 == icup) {
+ rccEnableTIM13(true);
+ rccResetTIM13();
+#if defined(STM32_TIM13CLK)
+ icup->clock = STM32_TIM13CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM14
+ if (&ICUD14 == icup) {
+ rccEnableTIM14(true);
+ rccResetTIM14();
+#if defined(STM32_TIM14CLK)
+ icup->clock = STM32_TIM14CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM15
+ if (&ICUD15 == icup) {
+ rccEnableTIM15(true);
+ rccResetTIM15();
+#if defined(STM32_TIM15CLK)
+ icup->clock = STM32_TIM15CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM20
+ if (&ICUD20 == icup) {
+ rccEnableTIM20(true);
+ rccResetTIM20();
+#if defined(STM32_TIM20CLK)
+ icup->clock = STM32_TIM20CLK;
+#else
+ icup->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM21
+ if (&ICUD21 == icup) {
+ rccEnableTIM21(true);
+ rccResetTIM21();
+#if defined(STM32_TIM21CLK)
+ icup->clock = STM32_TIM21CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_ICU_USE_TIM22
+ if (&ICUD22 == icup) {
+ rccEnableTIM22(true);
+ rccResetTIM22();
+#if defined(STM32_TIM22CLK)
+ icup->clock = STM32_TIM22CLK;
+#else
+ icup->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+ }
+ else {
+ /* Driver re-configuration scenario, it must be stopped first.*/
+ icup->tim->CR1 = 0; /* Timer disabled. */
+ icup->tim->CCR[0] = 0; /* Comparator 1 disabled. */
+ icup->tim->CCR[1] = 0; /* Comparator 2 disabled. */
+ icup->tim->CNT = 0; /* Counter reset to zero. */
+ }
+
+ /* Timer configuration.*/
+ icup->tim->SR = 0; /* Clear eventual pending IRQs. */
+ icup->tim->DIER = icup->config->dier & /* DMA-related DIER settings. */
+ ~STM32_TIM_DIER_IRQ_MASK;
+ psc = (icup->clock / icup->config->frequency) - 1;
+ osalDbgAssert((psc <= 0xFFFF) &&
+ ((psc + 1) * icup->config->frequency) == icup->clock,
+ "invalid frequency");
+ icup->tim->PSC = psc;
+ if (icup->config->arr == 0U) {
+ /* Zero is an invalid value and is turned in maximum value, also for
+ legacy configurations compatibility.*/
+ icup->tim->ARR = 0xFFFFFFFFU;
+ }
+ else {
+ icup->tim->ARR = icup->config->arr;
+ }
+
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ /* Selected input 1.
+ CCMR1_CC1S = 01 = CH1 Input on TI1.
+ CCMR1_CC2S = 10 = CH2 Input on TI1.*/
+ icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(1) | STM32_TIM_CCMR1_CC2S(2);
+
+ /* SMCR_TS = 101, input is TI1FP1.
+ SMCR_SMS = 100, reset on rising edge.*/
+ icup->tim->SMCR = STM32_TIM_SMCR_TS(5) | STM32_TIM_SMCR_SMS(4);
+
+ /* The CCER settings depend on the selected trigger mode.
+ ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge.
+ ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/
+ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
+ icup->tim->CCER = STM32_TIM_CCER_CC1E |
+ STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P;
+ else
+ icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P |
+ STM32_TIM_CCER_CC2E;
+
+ /* Direct pointers to the capture registers in order to make reading
+ data faster from within callbacks.*/
+ icup->wccrp = &icup->tim->CCR[1];
+ icup->pccrp = &icup->tim->CCR[0];
+ }
+ else {
+ /* Selected input 2.
+ CCMR1_CC1S = 10 = CH1 Input on TI2.
+ CCMR1_CC2S = 01 = CH2 Input on TI2.*/
+ icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(2) | STM32_TIM_CCMR1_CC2S(1);
+
+ /* SMCR_TS = 110, input is TI2FP2.
+ SMCR_SMS = 100, reset on rising edge.*/
+ icup->tim->SMCR = STM32_TIM_SMCR_TS(6) | STM32_TIM_SMCR_SMS(4);
+
+ /* The CCER settings depend on the selected trigger mode.
+ ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge.
+ ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/
+ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
+ icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P |
+ STM32_TIM_CCER_CC2E;
+ else
+ icup->tim->CCER = STM32_TIM_CCER_CC1E |
+ STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P;
+
+ /* Direct pointers to the capture registers in order to make reading
+ data faster from within callbacks.*/
+ icup->wccrp = &icup->tim->CCR[0];
+ icup->pccrp = &icup->tim->CCR[1];
+ }
+}
+
+/**
+ * @brief Deactivates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_stop(ICUDriver *icup) {
+
+ if (icup->state == ICU_READY) {
+ /* Clock deactivation.*/
+ icup->tim->CR1 = 0; /* Timer disabled. */
+ icup->tim->DIER = 0; /* All IRQs disabled. */
+ icup->tim->SR = 0; /* Clear eventual pending IRQs. */
+
+#if STM32_ICU_USE_TIM1
+ if (&ICUD1 == icup) {
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM1_UP_NUMBER);
+ nvicDisableVector(STM32_TIM1_CC_NUMBER);
+#endif
+ rccDisableTIM1();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM2
+ if (&ICUD2 == icup) {
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM2_NUMBER);
+#endif
+ rccDisableTIM2();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM3
+ if (&ICUD3 == icup) {
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM3_NUMBER);
+#endif
+ rccDisableTIM3();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM4
+ if (&ICUD4 == icup) {
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM4_NUMBER);
+#endif
+ rccDisableTIM4();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM5
+ if (&ICUD5 == icup) {
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM5_NUMBER);
+#endif
+ rccDisableTIM5();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM8
+ if (&ICUD8 == icup) {
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM8_UP_NUMBER);
+ nvicDisableVector(STM32_TIM8_CC_NUMBER);
+#endif
+ rccDisableTIM8();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM9
+ if (&ICUD9 == icup) {
+ rccDisableTIM9();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM10
+ if (&ICUD10 == icup) {
+ rccDisableTIM10();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM11
+ if (&ICUD11 == icup) {
+ rccDisableTIM11();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM12
+ if (&ICUD12 == icup) {
+ rccDisableTIM12();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM13
+ if (&ICUD13 == icup) {
+ rccDisableTIM13();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM14
+ if (&ICUD14 == icup) {
+ rccDisableTIM14();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM15
+ if (&ICUD15 == icup) {
+ rccDisableTIM15();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM20
+ if (&ICUD20 == icup) {
+ rccDisableTIM20();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM21
+ if (&ICUD21 == icup) {
+ rccDisableTIM21();
+ }
+#endif
+
+#if STM32_ICU_USE_TIM22
+ if (&ICUD22 == icup) {
+ rccDisableTIM22();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_start_capture(ICUDriver *icup) {
+
+ /* Triggering an UG and clearing the IRQ status.*/
+ icup->tim->EGR |= STM32_TIM_EGR_UG;
+ icup->tim->SR = 0;
+
+ /* Timer is started.*/
+ icup->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
+}
+
+/**
+ * @brief Waits for a completed capture.
+ * @note The operation is performed in polled mode.
+ * @note In order to use this function notifications must be disabled.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The capture status.
+ * @retval false if the capture is successful.
+ * @retval true if a timer overflow occurred.
+ *
+ * @notapi
+ */
+bool icu_lld_wait_capture(ICUDriver *icup) {
+
+ /* If the driver is still in the ICU_WAITING state then we need to wait
+ for the first activation edge.*/
+ if (icup->state == ICU_WAITING)
+ if (icu_lld_wait_edge(icup))
+ return true;
+
+ /* This edge marks the availability of a capture result.*/
+ return icu_lld_wait_edge(icup);
+}
+
+/**
+ * @brief Stops the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_stop_capture(ICUDriver *icup) {
+
+ /* Timer stopped.*/
+ icup->tim->CR1 = 0;
+
+ /* All interrupts disabled.*/
+ icup->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK;
+}
+
+/**
+ * @brief Enables notifications.
+ * @pre The ICU unit must have been activated using @p icuStart() and the
+ * capture started using @p icuStartCapture().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_enable_notifications(ICUDriver *icup) {
+ uint32_t dier = icup->tim->DIER;
+
+ /* If interrupts were already enabled then the operation is skipped.
+ This is done in order to avoid clearing the SR and risk losing
+ pending interrupts.*/
+ if ((dier & STM32_TIM_DIER_IRQ_MASK) == 0) {
+ /* Previously triggered IRQs are ignored, status cleared.*/
+ icup->tim->SR = 0;
+
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ /* Enabling periodic callback on CC1.*/
+ dier |= STM32_TIM_DIER_CC1IE;
+
+ /* Optionally enabling width callback on CC2.*/
+ if (icup->config->width_cb != NULL)
+ dier |= STM32_TIM_DIER_CC2IE;
+ }
+ else {
+ /* Enabling periodic callback on CC2.*/
+ dier |= STM32_TIM_DIER_CC2IE;
+
+ /* Optionally enabling width callback on CC1.*/
+ if (icup->config->width_cb != NULL)
+ dier |= STM32_TIM_DIER_CC1IE;
+ }
+
+ /* If an overflow callback is defined then also the overflow callback
+ is enabled.*/
+ if (icup->config->overflow_cb != NULL)
+ dier |= STM32_TIM_DIER_UIE;
+
+ /* One single atomic write.*/
+ icup->tim->DIER = dier;
+ }
+}
+
+/**
+ * @brief Disables notifications.
+ * @pre The ICU unit must have been activated using @p icuStart() and the
+ * capture started using @p icuStartCapture().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_disable_notifications(ICUDriver *icup) {
+
+ /* All interrupts disabled.*/
+ icup->tim->DIER &= ~STM32_TIM_DIER_IRQ_MASK;
+}
+
+/**
+ * @brief Shared IRQ handler.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_serve_interrupt(ICUDriver *icup) {
+ uint32_t sr;
+
+ sr = icup->tim->SR;
+ sr &= icup->tim->DIER & STM32_TIM_DIER_IRQ_MASK;
+ icup->tim->SR = ~sr;
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ if ((sr & STM32_TIM_SR_CC2IF) != 0)
+ _icu_isr_invoke_width_cb(icup);
+ if ((sr & STM32_TIM_SR_CC1IF) != 0)
+ _icu_isr_invoke_period_cb(icup);
+ }
+ else {
+ if ((sr & STM32_TIM_SR_CC1IF) != 0)
+ _icu_isr_invoke_width_cb(icup);
+ if ((sr & STM32_TIM_SR_CC2IF) != 0)
+ _icu_isr_invoke_period_cb(icup);
+ }
+ if ((sr & STM32_TIM_SR_UIF) != 0)
+ _icu_isr_invoke_overflow_cb(icup);
+}
+
+#endif /* HAL_USE_ICU */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h new file mode 100644 index 0000000..38c1907 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.h @@ -0,0 +1,893 @@ +/*
+ 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 TIMv1/hal_icu_lld.h
+ * @brief STM32 ICU subsystem low level driver header.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#ifndef HAL_ICU_LLD_H
+#define HAL_ICU_LLD_H
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+#include "stm32_tim.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief ICUD1 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM1 FALSE
+#endif
+
+/**
+ * @brief ICUD2 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM2 FALSE
+#endif
+
+/**
+ * @brief ICUD3 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM3 FALSE
+#endif
+
+/**
+ * @brief ICUD4 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM4 FALSE
+#endif
+
+/**
+ * @brief ICUD5 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM5 FALSE
+#endif
+
+/**
+ * @brief ICUD8 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM8) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM8 FALSE
+#endif
+
+/**
+ * @brief ICUD9 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD9 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM9) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM9 FALSE
+#endif
+
+/**
+ * @brief ICUD10 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD10 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM10) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM10 FALSE
+#endif
+
+/**
+ * @brief ICUD11 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD11 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM11) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM11 FALSE
+#endif
+
+/**
+ * @brief ICUD12 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD12 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM12) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM12 FALSE
+#endif
+
+/**
+ * @brief ICUD13 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD13 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM13) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM13 FALSE
+#endif
+
+/**
+ * @brief ICUD14 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD14 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM14) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM14 FALSE
+#endif
+
+/**
+ * @brief ICUD15 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD15 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM15) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM15 FALSE
+#endif
+
+/**
+ * @brief ICUD20 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD20 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM20) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM20 FALSE
+#endif
+
+/**
+ * @brief ICUD21 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD21 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM21) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM21 FALSE
+#endif
+
+/**
+ * @brief ICUD22 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD22 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_ICU_USE_TIM22) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM22 FALSE
+#endif
+
+/**
+ * @brief ICUD1 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM1_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD2 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM2_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD3 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM3_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD4 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM4_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD5 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM5_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD8 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM8_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD9 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM9_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD10 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM10_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD11 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM11_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD12 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM12_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD13 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM13_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD14 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM14_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD15 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM15_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM15_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD20 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM20_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM20_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD21 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM21_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM21_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD22 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM22_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM22_IRQ_PRIORITY 7
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_TIM1)
+#define STM32_HAS_TIM1 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM2)
+#define STM32_HAS_TIM2 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM3)
+#define STM32_HAS_TIM3 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM4)
+#define STM32_HAS_TIM4 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM5)
+#define STM32_HAS_TIM5 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM8)
+#define STM32_HAS_TIM8 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM9)
+#define STM32_HAS_TIM9 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM10)
+#define STM32_HAS_TIM10 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM11)
+#define STM32_HAS_TIM11 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM12)
+#define STM32_HAS_TIM12 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM13)
+#define STM32_HAS_TIM13 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM14)
+#define STM32_HAS_TIM14 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM15)
+#define STM32_HAS_TIM15 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM20)
+#define STM32_HAS_TIM20 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM21)
+#define STM32_HAS_TIM21 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM22)
+#define STM32_HAS_TIM22 FALSE
+#endif
+
+#if STM32_ICU_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM8 && !STM32_HAS_TIM8
+#error "TIM8 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM9 && !STM32_HAS_TIM9
+#error "TIM9 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM10 && !STM32_HAS_TIM10
+#error "TIM10 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM11 && !STM32_HAS_TIM11
+#error "TIM11 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM12 && !STM32_HAS_TIM12
+#error "TIM12 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM13 && !STM32_HAS_TIM13
+#error "TIM13 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM14 && !STM32_HAS_TIM14
+#error "TIM14 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM15 && !STM32_HAS_TIM15
+#error "TIM15 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM20 && !STM32_HAS_TIM20
+#error "TIM20 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM21 && !STM32_HAS_TIM21
+#error "TIM21 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM22 && !STM32_HAS_TIM22
+#error "TIM22 not present in the selected device"
+#endif
+
+#if !STM32_ICU_USE_TIM1 && !STM32_ICU_USE_TIM2 && \
+ !STM32_ICU_USE_TIM3 && !STM32_ICU_USE_TIM4 && \
+ !STM32_ICU_USE_TIM5 && !STM32_ICU_USE_TIM8 && \
+ !STM32_ICU_USE_TIM9 && !STM32_ICU_USE_TIM10 && \
+ !STM32_ICU_USE_TIM11 && !STM32_ICU_USE_TIM12 && \
+ !STM32_ICU_USE_TIM13 && !STM32_ICU_USE_TIM14 && \
+ !STM32_ICU_USE_TIM15 && !STM32_ICU_USE_TIM20 && \
+ !STM32_ICU_USE_TIM21 && !STM32_ICU_USE_TIM22
+#error "ICU driver activated but no TIM peripheral assigned"
+#endif
+
+/* Checks on allocation of TIMx units.*/
+#if STM32_ICU_USE_TIM1
+#if defined(STM32_TIM1_IS_USED)
+#error "ICUD1 requires TIM1 but the timer is already used"
+#else
+#define STM32_TIM1_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM2
+#if defined(STM32_TIM2_IS_USED)
+#error "ICUD2 requires TIM2 but the timer is already used"
+#else
+#define STM32_TIM2_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM3
+#if defined(STM32_TIM3_IS_USED)
+#error "ICUD3 requires TIM3 but the timer is already used"
+#else
+#define STM32_TIM3_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM4
+#if defined(STM32_TIM4_IS_USED)
+#error "ICUD4 requires TIM4 but the timer is already used"
+#else
+#define STM32_TIM4_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM5
+#if defined(STM32_TIM5_IS_USED)
+#error "ICUD5 requires TIM5 but the timer is already used"
+#else
+#define STM32_TIM5_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM8
+#if defined(STM32_TIM8_IS_USED)
+#error "ICUD8 requires TIM8 but the timer is already used"
+#else
+#define STM32_TIM8_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM9
+#if defined(STM32_TIM9_IS_USED)
+#error "ICUD9 requires TIM9 but the timer is already used"
+#else
+#define STM32_TIM9_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM10
+#if defined(STM32_TIM10_IS_USED)
+#error "ICUD10 requires TIM10 but the timer is already used"
+#else
+#define STM32_TIM10_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM11
+#if defined(STM32_TIM11_IS_USED)
+#error "ICUD11 requires TIM11 but the timer is already used"
+#else
+#define STM32_TIM11_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM12
+#if defined(STM32_TIM12_IS_USED)
+#error "ICUD12 requires TIM12 but the timer is already used"
+#else
+#define STM32_TIM12_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM13
+#if defined(STM32_TIM13_IS_USED)
+#error "ICUD13 requires TIM13 but the timer is already used"
+#else
+#define STM32_TIM13_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM14
+#if defined(STM32_TIM14_IS_USED)
+#error "ICUD14 requires TIM14 but the timer is already used"
+#else
+#define STM32_TIM14_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM15
+#if defined(STM32_TIM15_IS_USED)
+#error "ICUD15 requires TIM15 but the timer is already used"
+#else
+#define STM32_TIM15_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM20
+#if defined(STM32_TIM20_IS_USED)
+#error "ICUD20 requires TIM20 but the timer is already used"
+#else
+#define STM32_TIM20_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM21
+#if defined(STM32_TIM21_IS_USED)
+#error "ICUD21 requires TIM21 but the timer is already used"
+#else
+#define STM32_TIM21_IS_USED
+#endif
+#endif
+
+#if STM32_ICU_USE_TIM22
+#if defined(STM32_TIM22_IS_USED)
+#error "ICUD22 requires TIM22 but the timer is already used"
+#else
+#define STM32_TIM22_IS_USED
+#endif
+#endif
+
+/* IRQ priority checks.*/
+#if STM32_ICU_USE_TIM1 && !defined(STM32_TIM1_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM1"
+#endif
+
+#if STM32_ICU_USE_TIM2 && !defined(STM32_TIM2_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM2"
+#endif
+
+#if STM32_ICU_USE_TIM3 && !defined(STM32_TIM3_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM3"
+#endif
+
+#if STM32_ICU_USE_TIM4 && !defined(STM32_TIM4_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM4"
+#endif
+
+#if STM32_ICU_USE_TIM5 && !defined(STM32_TIM5_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM5"
+#endif
+
+#if STM32_ICU_USE_TIM8 && !defined(STM32_TIM8_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM8_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM8"
+#endif
+
+#if STM32_ICU_USE_TIM9 && !defined(STM32_TIM9_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM9_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM9"
+#endif
+
+#if STM32_ICU_USE_TIM10 && !defined(STM32_TIM10_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM10_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM10"
+#endif
+
+#if STM32_ICU_USE_TIM11 && !defined(STM32_TIM11_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM11_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM11"
+#endif
+
+#if STM32_ICU_USE_TIM12 && !defined(STM32_TIM12_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM12_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM12"
+#endif
+
+#if STM32_ICU_USE_TIM13 && !defined(STM32_TIM13_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM13_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM13"
+#endif
+
+#if STM32_ICU_USE_TIM14 && !defined(STM32_TIM14_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM14_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM14"
+#endif
+
+#if STM32_ICU_USE_TIM15 && !defined(STM32_TIM15_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM15_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM15"
+#endif
+
+#if STM32_ICU_USE_TIM20 && !defined(STM32_TIM20_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM20_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM20"
+#endif
+
+#if STM32_ICU_USE_TIM21 && !defined(STM32_TIM21_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM21_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM21"
+#endif
+
+#if STM32_ICU_USE_TIM22 && !defined(STM32_TIM22_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ICU_TIM22_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM22"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU driver mode.
+ */
+typedef enum {
+ ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
+ ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */
+} icumode_t;
+
+/**
+ * @brief ICU frequency type.
+ */
+typedef uint32_t icufreq_t;
+
+/**
+ * @brief ICU channel type.
+ */
+typedef enum {
+ ICU_CHANNEL_1 = 0, /**< Use TIMxCH1. */
+ ICU_CHANNEL_2 = 1, /**< Use TIMxCH2. */
+} icuchannel_t;
+
+/**
+ * @brief ICU counter type.
+ */
+typedef uint32_t icucnt_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Driver mode.
+ */
+ icumode_t mode;
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ icufreq_t frequency;
+ /**
+ * @brief Callback for pulse width measurement.
+ */
+ icucallback_t width_cb;
+ /**
+ * @brief Callback for cycle period measurement.
+ */
+ icucallback_t period_cb;
+ /**
+ * @brief Callback for timer overflow.
+ */
+ icucallback_t overflow_cb;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Timer input channel to be used.
+ * @note Only inputs TIMx 1 and 2 are supported.
+ */
+ icuchannel_t channel;
+ /**
+ * @brief TIM DIER register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ * @note Only the DMA-related bits can be specified in this field.
+ */
+ uint32_t dier;
+ /**
+ * @brief TIM ARR register initialization data.
+ * @note The value of this field should normally be equal to 0xFFFFFFFFU.
+ */
+ uint32_t arr;
+} ICUConfig;
+
+/**
+ * @brief Structure representing an ICU driver.
+ */
+struct ICUDriver {
+ /**
+ * @brief Driver state.
+ */
+ icustate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const ICUConfig *config;
+#if defined(ICU_DRIVER_EXT_FIELDS)
+ ICU_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
+ * @brief Pointer to the TIMx registers block.
+ */
+ stm32_tim_t *tim;
+ /**
+ * @brief CCR register used for width capture.
+ */
+ volatile uint32_t *wccrp;
+ /**
+ * @brief CCR register used for period capture.
+ */
+ volatile uint32_t *pccrp;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Returns the width of the latest pulse.
+ * @details The pulse width is defined as number of ticks between the start
+ * edge and the stop edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+#define icu_lld_get_width(icup) (*((icup)->wccrp) + 1)
+
+/**
+ * @brief Returns the width of the latest cycle.
+ * @details The cycle width is defined as number of ticks between a start
+ * edge and the next start edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+#define icu_lld_get_period(icup) (*((icup)->pccrp) + 1)
+
+/**
+ * @brief Check on notifications status.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The notifications status.
+ * @retval false if notifications are not enabled.
+ * @retval true if notifications are enabled.
+ *
+ * @notapi
+ */
+#define icu_lld_are_notifications_enabled(icup) \
+ (bool)(((icup)->tim->DIER & STM32_TIM_DIER_IRQ_MASK) != 0)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD1;
+#endif
+
+#if STM32_ICU_USE_TIM2 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD2;
+#endif
+
+#if STM32_ICU_USE_TIM3 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD3;
+#endif
+
+#if STM32_ICU_USE_TIM4 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD4;
+#endif
+
+#if STM32_ICU_USE_TIM5 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD5;
+#endif
+
+#if STM32_ICU_USE_TIM8 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD8;
+#endif
+
+#if STM32_ICU_USE_TIM9 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD9;
+#endif
+
+#if STM32_ICU_USE_TIM10 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD10;
+#endif
+
+#if STM32_ICU_USE_TIM11 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD11;
+#endif
+
+#if STM32_ICU_USE_TIM12 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD12;
+#endif
+
+#if STM32_ICU_USE_TIM13 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD13;
+#endif
+
+#if STM32_ICU_USE_TIM14 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD14;
+#endif
+
+#if STM32_ICU_USE_TIM15 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD15;
+#endif
+
+#if STM32_ICU_USE_TIM20 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD20;
+#endif
+
+#if STM32_ICU_USE_TIM21 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD21;
+#endif
+
+#if STM32_ICU_USE_TIM22 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD22;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void icu_lld_init(void);
+ void icu_lld_start(ICUDriver *icup);
+ void icu_lld_stop(ICUDriver *icup);
+ void icu_lld_start_capture(ICUDriver *icup);
+ bool icu_lld_wait_capture(ICUDriver *icup);
+ void icu_lld_stop_capture(ICUDriver *icup);
+ void icu_lld_enable_notifications(ICUDriver *icup);
+ void icu_lld_disable_notifications(ICUDriver *icup);
+ void icu_lld_serve_interrupt(ICUDriver *icup);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ICU */
+
+#endif /* HAL_ICU_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c new file mode 100644 index 0000000..eb6bebc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c @@ -0,0 +1,1302 @@ +/*
+ 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 TIMv1/hal_pwm_lld.c
+ * @brief STM32 PWM subsystem low level driver header.
+ *
+ * @addtogroup PWM
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PWM || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief PWMD1 driver identifier.
+ * @note The driver PWMD1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_PWM_USE_TIM1 || defined(__DOXYGEN__)
+PWMDriver PWMD1;
+#endif
+
+/**
+ * @brief PWMD2 driver identifier.
+ * @note The driver PWMD2 allocates the timer TIM2 when enabled.
+ */
+#if STM32_PWM_USE_TIM2 || defined(__DOXYGEN__)
+PWMDriver PWMD2;
+#endif
+
+/**
+ * @brief PWMD3 driver identifier.
+ * @note The driver PWMD3 allocates the timer TIM3 when enabled.
+ */
+#if STM32_PWM_USE_TIM3 || defined(__DOXYGEN__)
+PWMDriver PWMD3;
+#endif
+
+/**
+ * @brief PWMD4 driver identifier.
+ * @note The driver PWMD4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_PWM_USE_TIM4 || defined(__DOXYGEN__)
+PWMDriver PWMD4;
+#endif
+
+/**
+ * @brief PWMD5 driver identifier.
+ * @note The driver PWMD5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_PWM_USE_TIM5 || defined(__DOXYGEN__)
+PWMDriver PWMD5;
+#endif
+
+/**
+ * @brief PWMD8 driver identifier.
+ * @note The driver PWMD8 allocates the timer TIM8 when enabled.
+ */
+#if STM32_PWM_USE_TIM8 || defined(__DOXYGEN__)
+PWMDriver PWMD8;
+#endif
+
+/**
+ * @brief PWMD9 driver identifier.
+ * @note The driver PWMD9 allocates the timer TIM9 when enabled.
+ */
+#if STM32_PWM_USE_TIM9 || defined(__DOXYGEN__)
+PWMDriver PWMD9;
+#endif
+
+/**
+ * @brief PWMD10 driver identifier.
+ * @note The driver PWMD10 allocates the timer TIM10 when enabled.
+ */
+#if STM32_PWM_USE_TIM10 || defined(__DOXYGEN__)
+PWMDriver PWMD10;
+#endif
+
+/**
+ * @brief PWMD11 driver identifier.
+ * @note The driver PWMD11 allocates the timer TIM11 when enabled.
+ */
+#if STM32_PWM_USE_TIM11 || defined(__DOXYGEN__)
+PWMDriver PWMD11;
+#endif
+
+/**
+ * @brief PWMD12 driver identifier.
+ * @note The driver PWMD12 allocates the timer TIM12 when enabled.
+ */
+#if STM32_PWM_USE_TIM12 || defined(__DOXYGEN__)
+PWMDriver PWMD12;
+#endif
+
+/**
+ * @brief PWMD13 driver identifier.
+ * @note The driver PWMD13 allocates the timer TIM13 when enabled.
+ */
+#if STM32_PWM_USE_TIM13 || defined(__DOXYGEN__)
+PWMDriver PWMD13;
+#endif
+
+/**
+ * @brief PWMD14 driver identifier.
+ * @note The driver PWMD14 allocates the timer TIM14 when enabled.
+ */
+#if STM32_PWM_USE_TIM14 || defined(__DOXYGEN__)
+PWMDriver PWMD14;
+#endif
+
+/**
+ * @brief PWMD15 driver identifier.
+ * @note The driver PWMD15 allocates the timer TIM15 when enabled.
+ */
+#if STM32_PWM_USE_TIM15 || defined(__DOXYGEN__)
+PWMDriver PWMD15;
+#endif
+
+/**
+ * @brief PWMD16 driver identifier.
+ * @note The driver PWMD16 allocates the timer TIM16 when enabled.
+ */
+#if STM32_PWM_USE_TIM16 || defined(__DOXYGEN__)
+PWMDriver PWMD16;
+#endif
+
+/**
+ * @brief PWMD17 driver identifier.
+ * @note The driver PWMD17 allocates the timer TIM17 when enabled.
+ */
+#if STM32_PWM_USE_TIM17 || defined(__DOXYGEN__)
+PWMDriver PWMD17;
+#endif
+
+/**
+ * @brief PWMD20 driver identifier.
+ * @note The driver PWMD20 allocates the timer TIM20 when enabled.
+ */
+#if STM32_PWM_USE_TIM20 || defined(__DOXYGEN__)
+PWMDriver PWMD20;
+#endif
+
+/**
+ * @brief PWMD21 driver identifier.
+ * @note The driver PWMD21 allocates the timer TIM21 when enabled.
+ */
+#if STM32_PWM_USE_TIM21 || defined(__DOXYGEN__)
+PWMDriver PWMD21;
+#endif
+
+/**
+ * @brief PWMD22 driver identifier.
+ * @note The driver PWMD22 allocates the timer TIM22 when enabled.
+ */
+#if STM32_PWM_USE_TIM22 || defined(__DOXYGEN__)
+PWMDriver PWMD22;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_PWM_USE_TIM1 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+#if !defined(STM32_TIM1_UP_HANDLER)
+#error "STM32_TIM1_UP_HANDLER not defined"
+#endif
+/**
+ * @brief TIM1 update interrupt handler.
+ * @note It is assumed that this interrupt is only activated if the callback
+ * pointer is not equal to @p NULL in order to not perform an extra
+ * check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(STM32_TIM1_CC_HANDLER)
+#error "STM32_TIM1_CC_HANDLER not defined"
+#endif
+/**
+ * @brief TIM1 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM1_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM1 */
+
+#if STM32_PWM_USE_TIM2 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+#if !defined(STM32_TIM2_HANDLER)
+#error "STM32_TIM2_HANDLER not defined"
+#endif
+/**
+ * @brief TIM2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM2_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM2 */
+
+#if STM32_PWM_USE_TIM3 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+#if !defined(STM32_TIM3_HANDLER)
+#error "STM32_TIM3_HANDLER not defined"
+#endif
+/**
+ * @brief TIM3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM3_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM3 */
+
+#if STM32_PWM_USE_TIM4 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+#if !defined(STM32_TIM4_HANDLER)
+#error "STM32_TIM4_HANDLER not defined"
+#endif
+/**
+ * @brief TIM4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM4_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM4 */
+
+#if STM32_PWM_USE_TIM5 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+#if !defined(STM32_TIM5_HANDLER)
+#error "STM32_TIM5_HANDLER not defined"
+#endif
+/**
+ * @brief TIM5 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM5_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM5 */
+
+#if STM32_PWM_USE_TIM8 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+#if !defined(STM32_TIM8_UP_HANDLER)
+#error "STM32_TIM8_UP_HANDLER not defined"
+#endif
+/**
+ * @brief TIM8 update interrupt handler.
+ * @note It is assumed that this interrupt is only activated if the callback
+ * pointer is not equal to @p NULL in order to not perform an extra
+ * check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(STM32_TIM8_CC_HANDLER)
+#error "STM32_TIM8_CC_HANDLER not defined"
+#endif
+/**
+ * @brief TIM8 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ pwm_lld_serve_interrupt(&PWMD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(STM32_TIM8_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM8 */
+
+#if STM32_PWM_USE_TIM9 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM9_SUPPRESS_ISR)
+#error "TIM9 ISR not defined by platform"
+#endif /* !defined(STM32_TIM9_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM9 */
+
+#if STM32_PWM_USE_TIM10 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM10_SUPPRESS_ISR)
+#error "TIM10 ISR not defined by platform"
+#endif /* !defined(STM32_TIM10_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM10 */
+
+#if STM32_PWM_USE_TIM11 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM11_SUPPRESS_ISR)
+#error "TIM11 ISR not defined by platform"
+#endif /* !defined(STM32_TIM11_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM11 */
+
+#if STM32_PWM_USE_TIM12 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM12_SUPPRESS_ISR)
+#error "TIM12 ISR not defined by platform"
+#endif /* !defined(STM32_TIM12_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM12 */
+
+#if STM32_PWM_USE_TIM13 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM13_SUPPRESS_ISR)
+#error "TIM13 ISR not defined by platform"
+#endif /* !defined(STM32_TIM13_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM13 */
+
+#if STM32_PWM_USE_TIM14 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM14_SUPPRESS_ISR)
+#error "TIM14 ISR not defined by platform"
+#endif /* !defined(STM32_TIM14_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM14 */
+
+#if STM32_PWM_USE_TIM15 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM15_SUPPRESS_ISR)
+#error "TIM15 ISR not defined by platform"
+#endif /* !defined(STM32_TIM15_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM15 */
+
+#if STM32_PWM_USE_TIM16 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM16_SUPPRESS_ISR)
+#error "TIM16 ISR not defined by platform"
+#endif /* !defined(STM32_TIM16_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM16 */
+
+#if STM32_PWM_USE_TIM17 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM17_SUPPRESS_ISR)
+#error "TIM17 ISR not defined by platform"
+#endif /* !defined(STM32_TIM17_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM17 */
+
+#if STM32_PWM_USE_TIM20 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM20_SUPPRESS_ISR)
+#error "TIM20 ISR not defined by platform"
+#endif /* !defined(STM32_TIM20_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM20 */
+
+#if STM32_PWM_USE_TIM21 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM21_SUPPRESS_ISR)
+#error "TIM21 ISR not defined by platform"
+#endif /* !defined(STM32_TIM21_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM21 */
+
+#if STM32_PWM_USE_TIM22 || defined(__DOXYGEN__)
+#if !defined(STM32_TIM22_SUPPRESS_ISR)
+#error "TIM22 ISR not defined by platform"
+#endif /* !defined(STM32_TIM22_SUPPRESS_ISR) */
+#endif /* STM32_PWM_USE_TIM22 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level PWM driver initialization.
+ *
+ * @notapi
+ */
+void pwm_lld_init(void) {
+
+#if STM32_PWM_USE_TIM1
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD1);
+ PWMD1.channels = STM32_TIM1_CHANNELS;
+ PWMD1.tim = STM32_TIM1;
+#endif
+
+#if STM32_PWM_USE_TIM2
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD2);
+ PWMD2.channels = STM32_TIM2_CHANNELS;
+ PWMD2.tim = STM32_TIM2;
+#endif
+
+#if STM32_PWM_USE_TIM3
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD3);
+ PWMD3.channels = STM32_TIM3_CHANNELS;
+ PWMD3.tim = STM32_TIM3;
+#endif
+
+#if STM32_PWM_USE_TIM4
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD4);
+ PWMD4.channels = STM32_TIM4_CHANNELS;
+ PWMD4.tim = STM32_TIM4;
+#endif
+
+#if STM32_PWM_USE_TIM5
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD5);
+ PWMD5.channels = STM32_TIM5_CHANNELS;
+ PWMD5.tim = STM32_TIM5;
+#endif
+
+#if STM32_PWM_USE_TIM8
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD8);
+ PWMD8.channels = STM32_TIM8_CHANNELS;
+ PWMD8.tim = STM32_TIM8;
+#endif
+
+#if STM32_PWM_USE_TIM9
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD9);
+ PWMD9.channels = STM32_TIM9_CHANNELS;
+ PWMD9.tim = STM32_TIM9;
+#endif
+
+#if STM32_PWM_USE_TIM10
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD10);
+ PWMD10.channels = STM32_TIM10_CHANNELS;
+ PWMD10.tim = STM32_TIM10;
+#endif
+
+#if STM32_PWM_USE_TIM11
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD11);
+ PWMD11.channels = STM32_TIM11_CHANNELS;
+ PWMD11.tim = STM32_TIM11;
+#endif
+
+#if STM32_PWM_USE_TIM12
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD12);
+ PWMD12.channels = STM32_TIM12_CHANNELS;
+ PWMD12.tim = STM32_TIM12;
+#endif
+
+#if STM32_PWM_USE_TIM13
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD13);
+ PWMD13.channels = STM32_TIM13_CHANNELS;
+ PWMD13.tim = STM32_TIM13;
+#endif
+
+#if STM32_PWM_USE_TIM14
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD14);
+ PWMD14.channels = STM32_TIM14_CHANNELS;
+ PWMD14.tim = STM32_TIM14;
+#endif
+
+#if STM32_PWM_USE_TIM15
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD15);
+ PWMD15.channels = STM32_TIM15_CHANNELS;
+ PWMD15.tim = STM32_TIM15;
+#endif
+
+#if STM32_PWM_USE_TIM16
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD16);
+ PWMD16.channels = STM32_TIM16_CHANNELS;
+ PWMD16.tim = STM32_TIM16;
+#endif
+
+#if STM32_PWM_USE_TIM17
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD17);
+ PWMD17.channels = STM32_TIM17_CHANNELS;
+ PWMD17.tim = STM32_TIM17;
+#endif
+
+#if STM32_PWM_USE_TIM20
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD20);
+ PWMD20.channels = STM32_TIM20_CHANNELS;
+ PWMD20.tim = STM32_TIM20;
+#endif
+
+#if STM32_PWM_USE_TIM21
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD21);
+ PWMD21.channels = STM32_TIM21_CHANNELS;
+ PWMD21.tim = STM32_TIM21;
+#endif
+
+#if STM32_PWM_USE_TIM22
+ /* Driver initialization.*/
+ pwmObjectInit(&PWMD22);
+ PWMD22.channels = STM32_TIM22_CHANNELS;
+ PWMD22.tim = STM32_TIM22;
+#endif
+}
+
+/**
+ * @brief Configures and activates the PWM peripheral.
+ * @note Starting a driver that is already in the @p PWM_READY state
+ * disables all the active channels.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_start(PWMDriver *pwmp) {
+ uint32_t psc;
+ uint32_t ccer;
+
+ if (pwmp->state == PWM_STOP) {
+ /* Clock activation and timer reset.*/
+#if STM32_PWM_USE_TIM1
+ if (&PWMD1 == pwmp) {
+ rccEnableTIM1(true);
+ rccResetTIM1();
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_PWM_TIM1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_PWM_TIM1_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM1CLK)
+ pwmp->clock = STM32_TIM1CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM2
+ if (&PWMD2 == pwmp) {
+ rccEnableTIM2(true);
+ rccResetTIM2();
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM2_NUMBER, STM32_PWM_TIM2_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM2CLK)
+ pwmp->clock = STM32_TIM2CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM3
+ if (&PWMD3 == pwmp) {
+ rccEnableTIM3(true);
+ rccResetTIM3();
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM3_NUMBER, STM32_PWM_TIM3_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM3CLK)
+ pwmp->clock = STM32_TIM3CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM4
+ if (&PWMD4 == pwmp) {
+ rccEnableTIM4(true);
+ rccResetTIM4();
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM4_NUMBER, STM32_PWM_TIM4_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM4CLK)
+ pwmp->clock = STM32_TIM4CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM5
+ if (&PWMD5 == pwmp) {
+ rccEnableTIM5(true);
+ rccResetTIM5();
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM5_NUMBER, STM32_PWM_TIM5_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM5CLK)
+ pwmp->clock = STM32_TIM5CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM8
+ if (&PWMD8 == pwmp) {
+ rccEnableTIM8(true);
+ rccResetTIM8();
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+ nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_PWM_TIM8_IRQ_PRIORITY);
+ nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_PWM_TIM8_IRQ_PRIORITY);
+#endif
+#if defined(STM32_TIM8CLK)
+ pwmp->clock = STM32_TIM8CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM9
+ if (&PWMD9 == pwmp) {
+ rccEnableTIM9(true);
+ rccResetTIM9();
+#if defined(STM32_TIM9CLK)
+ pwmp->clock = STM32_TIM9CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM10
+ if (&PWMD10 == pwmp) {
+ rccEnableTIM10(true);
+ rccResetTIM10();
+#if defined(STM32_TIM10CLK)
+ pwmp->clock = STM32_TIM10CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM11
+ if (&PWMD11 == pwmp) {
+ rccEnableTIM11(true);
+ rccResetTIM11();
+#if defined(STM32_TIM11CLK)
+ pwmp->clock = STM32_TIM11CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM12
+ if (&PWMD12 == pwmp) {
+ rccEnableTIM12(true);
+ rccResetTIM12();
+#if defined(STM32_TIM12CLK)
+ pwmp->clock = STM32_TIM12CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM13
+ if (&PWMD13 == pwmp) {
+ rccEnableTIM13(true);
+ rccResetTIM13();
+#if defined(STM32_TIM13CLK)
+ pwmp->clock = STM32_TIM13CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM14
+ if (&PWMD14 == pwmp) {
+ rccEnableTIM14(true);
+ rccResetTIM14();
+#if defined(STM32_TIM14CLK)
+ pwmp->clock = STM32_TIM14CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM15
+ if (&PWMD15 == pwmp) {
+ rccEnableTIM15(true);
+ rccResetTIM15();
+#if defined(STM32_TIM15CLK)
+ pwmp->clock = STM32_TIM15CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM16
+ if (&PWMD16 == pwmp) {
+ rccEnableTIM16(true);
+ rccResetTIM16();
+#if defined(STM32_TIM16CLK)
+ pwmp->clock = STM32_TIM16CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM17
+ if (&PWMD17 == pwmp) {
+ rccEnableTIM17(true);
+ rccResetTIM17();
+#if defined(STM32_TIM17CLK)
+ pwmp->clock = STM32_TIM17CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM20
+ if (&PWMD20 == pwmp) {
+ rccEnableTIM20(true);
+ rccResetTIM20();
+#if defined(STM32_TIM20CLK)
+ pwmp->clock = STM32_TIM20CLK;
+#else
+ pwmp->clock = STM32_TIMCLK2;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM21
+ if (&PWMD21 == pwmp) {
+ rccEnableTIM21(true);
+ rccResetTIM21();
+#if defined(STM32_TIM21CLK)
+ pwmp->clock = STM32_TIM21CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+#if STM32_PWM_USE_TIM22
+ if (&PWMD22 == pwmp) {
+ rccEnableTIM22(true);
+ rccResetTIM22();
+#if defined(STM32_TIM22CLK)
+ pwmp->clock = STM32_TIM22CLK;
+#else
+ pwmp->clock = STM32_TIMCLK1;
+#endif
+ }
+#endif
+
+ /* All channels configured in PWM1 mode with preload enabled and will
+ stay that way until the driver is stopped.*/
+ pwmp->tim->CCMR1 = STM32_TIM_CCMR1_OC1M(6) | STM32_TIM_CCMR1_OC1PE |
+ STM32_TIM_CCMR1_OC2M(6) | STM32_TIM_CCMR1_OC2PE;
+ pwmp->tim->CCMR2 = STM32_TIM_CCMR2_OC3M(6) | STM32_TIM_CCMR2_OC3PE |
+ STM32_TIM_CCMR2_OC4M(6) | STM32_TIM_CCMR2_OC4PE;
+#if STM32_TIM_MAX_CHANNELS > 4
+ pwmp->tim->CCMR3 = STM32_TIM_CCMR3_OC5M(6) | STM32_TIM_CCMR3_OC5PE |
+ STM32_TIM_CCMR3_OC6M(6) | STM32_TIM_CCMR3_OC6PE;
+#endif
+ }
+ else {
+ /* Driver re-configuration scenario, it must be stopped first.*/
+ pwmp->tim->CR1 = 0; /* Timer disabled. */
+ pwmp->tim->CCR[0] = 0; /* Comparator 1 disabled. */
+ pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */
+ pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */
+ pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */
+#if STM32_TIM_MAX_CHANNELS > 4
+ if (pwmp->channels > 4) {
+ pwmp->tim->CCXR[0] = 0; /* Comparator 5 disabled. */
+ pwmp->tim->CCXR[1] = 0; /* Comparator 6 disabled. */
+ }
+#endif
+ pwmp->tim->CNT = 0; /* Counter reset to zero. */
+ }
+
+ /* Timer configuration.*/
+ psc = (pwmp->clock / pwmp->config->frequency) - 1;
+ osalDbgAssert((psc <= 0xFFFF) &&
+ ((psc + 1) * pwmp->config->frequency) == pwmp->clock,
+ "invalid frequency");
+ pwmp->tim->PSC = psc;
+ pwmp->tim->ARR = pwmp->period - 1;
+ pwmp->tim->CR2 = pwmp->config->cr2;
+
+ /* Output enables and polarities setup.*/
+ ccer = 0;
+ switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) {
+ case PWM_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC1P;
+ /* Falls through.*/
+ case PWM_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC1E;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) {
+ case PWM_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC2P;
+ /* Falls through.*/
+ case PWM_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC2E;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[2].mode & PWM_OUTPUT_MASK) {
+ case PWM_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC3P;
+ /* Falls through.*/
+ case PWM_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC3E;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[3].mode & PWM_OUTPUT_MASK) {
+ case PWM_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC4P;
+ /* Falls through.*/
+ case PWM_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC4E;
+ /* Falls through.*/
+ default:
+ ;
+ }
+#if STM32_PWM_USE_ADVANCED
+#if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && !STM32_PWM_USE_TIM20
+ if (&PWMD1 == pwmp) {
+#endif
+#if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && !STM32_PWM_USE_TIM20
+ if (&PWMD8 == pwmp) {
+#endif
+#if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && !STM32_PWM_USE_TIM20
+ if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp)) {
+#endif
+#if !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20
+ if (&PWMD20 == pwmp) {
+#endif
+#if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20
+ if ((&PWMD1 == pwmp) || (&PWMD20 == pwmp)) {
+#endif
+#if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20
+ if ((&PWMD8 == pwmp) || (&PWMD20 == pwmp)) {
+#endif
+#if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 && STM32_PWM_USE_TIM20
+ if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp) || (&PWMD20 == pwmp)) {
+#endif
+ switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC1NP;
+ /* Falls through.*/
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC1NE;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC2NP;
+ /* Falls through.*/
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC2NE;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[2].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC3NP;
+ /* Falls through.*/
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC3NE;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[3].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= STM32_TIM_CCER_CC4NP;
+ /* Falls through.*/
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= STM32_TIM_CCER_CC4NE;
+ /* Falls through.*/
+ default:
+ ;
+ }
+ }
+#endif /* STM32_PWM_USE_ADVANCED*/
+
+ pwmp->tim->CCER = ccer;
+ pwmp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
+ pwmp->tim->SR = 0; /* Clear pending IRQs. */
+ pwmp->tim->DIER = pwmp->config->dier & /* DMA-related DIER settings. */
+ ~STM32_TIM_DIER_IRQ_MASK;
+#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 || STM32_PWM_USE_TIM20
+#if STM32_PWM_USE_ADVANCED
+ pwmp->tim->BDTR = pwmp->config->bdtr | STM32_TIM_BDTR_MOE;
+#else
+ pwmp->tim->BDTR = STM32_TIM_BDTR_MOE;
+#endif
+#endif
+ /* Timer configured and started.*/
+ pwmp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS |
+ STM32_TIM_CR1_CEN;
+}
+
+/**
+ * @brief Deactivates the PWM peripheral.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_stop(PWMDriver *pwmp) {
+
+ /* If in ready state then disables the PWM clock.*/
+ if (pwmp->state == PWM_READY) {
+ pwmp->tim->CR1 = 0; /* Timer disabled. */
+ pwmp->tim->DIER = 0; /* All IRQs disabled. */
+ pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
+#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 || STM32_PWM_USE_TIM20
+ pwmp->tim->BDTR = 0;
+#endif
+
+#if STM32_PWM_USE_TIM1
+ if (&PWMD1 == pwmp) {
+#if !defined(STM32_TIM1_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM1_UP_NUMBER);
+ nvicDisableVector(STM32_TIM1_CC_NUMBER);
+#endif
+ rccDisableTIM1();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM2
+ if (&PWMD2 == pwmp) {
+#if !defined(STM32_TIM2_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM2_NUMBER);
+#endif
+ rccDisableTIM2();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM3
+ if (&PWMD3 == pwmp) {
+#if !defined(STM32_TIM3_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM3_NUMBER);
+#endif
+ rccDisableTIM3();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM4
+ if (&PWMD4 == pwmp) {
+#if !defined(STM32_TIM4_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM4_NUMBER);
+#endif
+ rccDisableTIM4();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM5
+ if (&PWMD5 == pwmp) {
+#if !defined(STM32_TIM5_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM5_NUMBER);
+#endif
+ rccDisableTIM5();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM8
+ if (&PWMD8 == pwmp) {
+#if !defined(STM32_TIM8_SUPPRESS_ISR)
+ nvicDisableVector(STM32_TIM8_UP_NUMBER);
+ nvicDisableVector(STM32_TIM8_CC_NUMBER);
+#endif
+ rccDisableTIM8();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM9
+ if (&PWMD9 == pwmp) {
+ rccDisableTIM9();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM10
+ if (&PWMD10 == pwmp) {
+ rccDisableTIM10();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM11
+ if (&PWMD11 == pwmp) {
+ rccDisableTIM11();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM12
+ if (&PWMD12 == pwmp) {
+ rccDisableTIM12();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM13
+ if (&PWMD13 == pwmp) {
+ rccDisableTIM13();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM14
+ if (&PWMD14 == pwmp) {
+ rccDisableTIM14();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM15
+ if (&PWMD15 == pwmp) {
+ rccDisableTIM15();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM16
+ if (&PWMD16 == pwmp) {
+ rccDisableTIM16();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM17
+ if (&PWMD17 == pwmp) {
+ rccDisableTIM17();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM20
+ if (&PWMD20 == pwmp) {
+ rccDisableTIM20();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM21
+ if (&PWMD21 == pwmp) {
+ rccDisableTIM21();
+ }
+#endif
+
+#if STM32_PWM_USE_TIM22
+ if (&PWMD22 == pwmp) {
+ rccDisableTIM22();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Enables a PWM channel.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is active using the specified configuration.
+ * @note The function has effect at the next cycle start.
+ * @note Channel notification is not enabled.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ * @param[in] width PWM pulse width as clock pulses number
+ *
+ * @notapi
+ */
+void pwm_lld_enable_channel(PWMDriver *pwmp,
+ pwmchannel_t channel,
+ pwmcnt_t width) {
+
+ /* Changing channel duty cycle on the fly.*/
+#if STM32_TIM_MAX_CHANNELS <= 4
+ pwmp->tim->CCR[channel] = width;
+#else
+ if (channel < 4)
+ pwmp->tim->CCR[channel] = width;
+ else
+ pwmp->tim->CCXR[channel - 4] = width;
+#endif
+}
+
+/**
+ * @brief Disables a PWM channel and its notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is disabled and its output line returned to the
+ * idle state.
+ * @note The function has effect at the next cycle start.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
+
+#if STM32_TIM_MAX_CHANNELS <= 4
+ pwmp->tim->CCR[channel] = 0;
+ pwmp->tim->DIER &= ~(2 << channel);
+#else
+ if (channel < 4) {
+ pwmp->tim->CCR[channel] = 0;
+ pwmp->tim->DIER &= ~(2 << channel);
+ }
+ else
+ pwmp->tim->CCXR[channel - 4] = 0;
+#endif
+}
+
+/**
+ * @brief Enables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
+ uint32_t dier = pwmp->tim->DIER;
+
+ /* If the IRQ is not already enabled care must be taken to clear it,
+ it is probably already pending because the timer is running.*/
+ if ((dier & STM32_TIM_DIER_UIE) == 0) {
+ pwmp->tim->SR = ~STM32_TIM_SR_UIF;
+ pwmp->tim->DIER = dier | STM32_TIM_DIER_UIE;
+ }
+}
+
+/**
+ * @brief Disables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
+
+ pwmp->tim->DIER &= ~STM32_TIM_DIER_UIE;
+}
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel) {
+ uint32_t dier = pwmp->tim->DIER;
+
+#if STM32_TIM_MAX_CHANNELS > 4
+ /* Channels 4 and 5 do not support callbacks.*/
+ osalDbgAssert(channel < 4, "callback not supported");
+#endif
+
+ /* If the IRQ is not already enabled care must be taken to clear it,
+ it is probably already pending because the timer is running.*/
+ if ((dier & (2 << channel)) == 0) {
+ pwmp->tim->SR = ~(2 << channel);
+ pwmp->tim->DIER = dier | (2 << channel);
+ }
+}
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel) {
+
+ pwmp->tim->DIER &= ~(2 << channel);
+}
+
+/**
+ * @brief Common TIM2...TIM5,TIM9 IRQ handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
+ uint32_t sr;
+
+ sr = pwmp->tim->SR;
+ sr &= pwmp->tim->DIER & STM32_TIM_DIER_IRQ_MASK;
+ pwmp->tim->SR = ~sr;
+ if (((sr & STM32_TIM_SR_CC1IF) != 0) &&
+ (pwmp->config->channels[0].callback != NULL))
+ pwmp->config->channels[0].callback(pwmp);
+ if (((sr & STM32_TIM_SR_CC2IF) != 0) &&
+ (pwmp->config->channels[1].callback != NULL))
+ pwmp->config->channels[1].callback(pwmp);
+ if (((sr & STM32_TIM_SR_CC3IF) != 0) &&
+ (pwmp->config->channels[2].callback != NULL))
+ pwmp->config->channels[2].callback(pwmp);
+ if (((sr & STM32_TIM_SR_CC4IF) != 0) &&
+ (pwmp->config->channels[3].callback != NULL))
+ pwmp->config->channels[3].callback(pwmp);
+ if (((sr & STM32_TIM_SR_UIF) != 0) && (pwmp->config->callback != NULL))
+ pwmp->config->callback(pwmp);
+}
+
+#endif /* HAL_USE_PWM */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h new file mode 100644 index 0000000..4cf0f7c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.h @@ -0,0 +1,1034 @@ +/*
+ 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 TIMv1/hal_pwm_lld.h
+ * @brief STM32 PWM subsystem low level driver header.
+ *
+ * @addtogroup PWM
+ * @{
+ */
+
+#ifndef HAL_PWM_LLD_H
+#define HAL_PWM_LLD_H
+
+#if HAL_USE_PWM || defined(__DOXYGEN__)
+
+#include "stm32_tim.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of PWM channels per PWM driver.
+ */
+#define PWM_CHANNELS STM32_TIM_MAX_CHANNELS
+
+/**
+ * @name STM32-specific PWM complementary output mode macros
+ * @{
+ */
+/**
+ * @brief Complementary output modes mask.
+ * @note This is an STM32-specific setting.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_MASK 0xF0
+
+/**
+ * @brief Complementary output not driven.
+ * @note This is an STM32-specific setting.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_DISABLED 0x00
+
+/**
+ * @brief Complementary output, active is logic level one.
+ * @note This is an STM32-specific setting.
+ * @note This setting is only available if the configuration option
+ * @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced
+ * timers TIM1 and TIM8.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH 0x10
+
+/**
+ * @brief Complementary output, active is logic level zero.
+ * @note This is an STM32-specific setting.
+ * @note This setting is only available if the configuration option
+ * @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced
+ * timers TIM1 and TIM8.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW 0x20
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief If advanced timer features switch.
+ * @details If set to @p TRUE the advanced features for TIM1 and TIM8 are
+ * enabled.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_ADVANCED) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_ADVANCED FALSE
+#endif
+
+/**
+ * @brief PWMD1 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM1 FALSE
+#endif
+
+/**
+ * @brief PWMD2 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM2 FALSE
+#endif
+
+/**
+ * @brief PWMD3 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM3 FALSE
+#endif
+
+/**
+ * @brief PWMD4 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM4 FALSE
+#endif
+
+/**
+ * @brief PWMD5 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM5 FALSE
+#endif
+
+/**
+ * @brief PWMD8 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM8) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM8 FALSE
+#endif
+
+/**
+ * @brief PWMD9 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD9 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM9) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM9 FALSE
+#endif
+
+/**
+ * @brief PWMD10 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD10 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM10) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM10 FALSE
+#endif
+
+/**
+ * @brief PWMD11 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD11 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM11) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM11 FALSE
+#endif
+
+/**
+ * @brief PWMD12 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD12 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM12) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM12 FALSE
+#endif
+
+/**
+ * @brief PWMD13 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD13 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM13) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM13 FALSE
+#endif
+
+/**
+ * @brief PWMD14 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD14 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM14) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM14 FALSE
+#endif
+
+/**
+ * @brief PWMD15 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD15 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM15) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM15 FALSE
+#endif
+
+/**
+ * @brief PWMD16 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD16 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM16) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM16 FALSE
+#endif
+
+/**
+ * @brief PWMD17 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD17 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM17) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM17 FALSE
+#endif
+
+/**
+ * @brief PWMD20 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD20 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM20) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM20 FALSE
+#endif
+
+/**
+ * @brief PWMD21 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD21 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM21) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM21 FALSE
+#endif
+
+/**
+ * @brief PWMD22 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD22 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_PWM_USE_TIM22) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_TIM22 FALSE
+#endif
+
+/**
+ * @brief PWMD1 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM1_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD2 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM2_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD3 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM3_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD4 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM4_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD5 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM5_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD8 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM8_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD9 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM9_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD10 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM10_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM10_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD11 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM11_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD12 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM12_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD13 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM13_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM13_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD14 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM14_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD15 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM15_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM15_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD16 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM16_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM16_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD17 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM17_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM17_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD20 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM20_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM20_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD21 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM21_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM21_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief PWMD22 interrupt priority level setting.
+ */
+#if !defined(STM32_PWM_TIM22_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_PWM_TIM22_IRQ_PRIORITY 7
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Configuration checks. */
+/*===========================================================================*/
+
+#if !defined(STM32_HAS_TIM1)
+#define STM32_HAS_TIM1 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM2)
+#define STM32_HAS_TIM2 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM3)
+#define STM32_HAS_TIM3 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM4)
+#define STM32_HAS_TIM4 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM5)
+#define STM32_HAS_TIM5 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM8)
+#define STM32_HAS_TIM8 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM9)
+#define STM32_HAS_TIM9 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM10)
+#define STM32_HAS_TIM10 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM11)
+#define STM32_HAS_TIM11 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM12)
+#define STM32_HAS_TIM12 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM13)
+#define STM32_HAS_TIM13 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM14)
+#define STM32_HAS_TIM14 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM15)
+#define STM32_HAS_TIM15 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM16)
+#define STM32_HAS_TIM16 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM17)
+#define STM32_HAS_TIM17 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM20)
+#define STM32_HAS_TIM20 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM21)
+#define STM32_HAS_TIM21 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM22)
+#define STM32_HAS_TIM22 FALSE
+#endif
+
+#if STM32_PWM_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM8 && !STM32_HAS_TIM8
+#error "TIM8 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM9 && !STM32_HAS_TIM9
+#error "TIM9 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM10 && !STM32_HAS_TIM10
+#error "TIM10 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM11 && !STM32_HAS_TIM11
+#error "TIM11 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM12 && !STM32_HAS_TIM12
+#error "TIM12 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM13 && !STM32_HAS_TIM13
+#error "TIM13 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM14 && !STM32_HAS_TIM14
+#error "TIM14 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM15 && !STM32_HAS_TIM15
+#error "TIM15 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM16 && !STM32_HAS_TIM16
+#error "TIM16 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM17 && !STM32_HAS_TIM17
+#error "TIM17 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM20 && !STM32_HAS_TIM20
+#error "TIM20 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM21 && !STM32_HAS_TIM21
+#error "TIM21 not present in the selected device"
+#endif
+
+#if STM32_PWM_USE_TIM22 && !STM32_HAS_TIM22
+#error "TIM22 not present in the selected device"
+#endif
+
+#if !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM2 && \
+ !STM32_PWM_USE_TIM3 && !STM32_PWM_USE_TIM4 && \
+ !STM32_PWM_USE_TIM5 && !STM32_PWM_USE_TIM8 && \
+ !STM32_PWM_USE_TIM9 && !STM32_PWM_USE_TIM10 && \
+ !STM32_PWM_USE_TIM11 && !STM32_PWM_USE_TIM11 && \
+ !STM32_PWM_USE_TIM13 && !STM32_PWM_USE_TIM13 && \
+ !STM32_PWM_USE_TIM15 && !STM32_PWM_USE_TIM15 && \
+ !STM32_PWM_USE_TIM17 && !STM32_PWM_USE_TIM20 && \
+ !STM32_PWM_USE_TIM21 && !STM32_PWM_USE_TIM22
+#error "PWM driver activated but no TIM peripheral assigned"
+#endif
+
+#if STM32_PWM_USE_ADVANCED && !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 && \
+ !STM32_PWM_USE_TIM20
+#error "advanced mode selected but no advanced timer assigned"
+#endif
+
+/* Checks on allocation of TIMx units.*/
+#if STM32_PWM_USE_TIM1
+#if defined(STM32_TIM1_IS_USED)
+#error "PWMD1 requires TIM1 but the timer is already used"
+#else
+#define STM32_TIM1_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM2
+#if defined(STM32_TIM2_IS_USED)
+#error "PWMD2 requires TIM2 but the timer is already used"
+#else
+#define STM32_TIM2_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM3
+#if defined(STM32_TIM3_IS_USED)
+#error "PWMD3 requires TIM3 but the timer is already used"
+#else
+#define STM32_TIM3_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM4
+#if defined(STM32_TIM4_IS_USED)
+#error "PWMD4 requires TIM4 but the timer is already used"
+#else
+#define STM32_TIM4_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM5
+#if defined(STM32_TIM5_IS_USED)
+#error "PWMD5 requires TIM5 but the timer is already used"
+#else
+#define STM32_TIM5_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM8
+#if defined(STM32_TIM8_IS_USED)
+#error "PWMD8 requires TIM8 but the timer is already used"
+#else
+#define STM32_TIM8_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM9
+#if defined(STM32_TIM9_IS_USED)
+#error "PWMD9 requires TIM9 but the timer is already used"
+#else
+#define STM32_TIM9_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM10
+#if defined(STM32_TIM10_IS_USED)
+#error "PWMD10 requires TIM10 but the timer is already used"
+#else
+#define STM32_TIM10_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM11
+#if defined(STM32_TIM11_IS_USED)
+#error "PWMD11 requires TIM11 but the timer is already used"
+#else
+#define STM32_TIM11_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM12
+#if defined(STM32_TIM12_IS_USED)
+#error "PWMD12 requires TIM12 but the timer is already used"
+#else
+#define STM32_TIM12_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM13
+#if defined(STM32_TIM13_IS_USED)
+#error "PWMD13 requires TIM13 but the timer is already used"
+#else
+#define STM32_TIM13_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM14
+#if defined(STM32_TIM14_IS_USED)
+#error "PWMD14 requires TIM14 but the timer is already used"
+#else
+#define STM32_TIM14_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM15
+#if defined(STM32_TIM15_IS_USED)
+#error "PWMD15 requires TIM15 but the timer is already used"
+#else
+#define STM32_TIM15_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM16
+#if defined(STM32_TIM16_IS_USED)
+#error "PWMD16 requires TIM16 but the timer is already used"
+#else
+#define STM32_TIM16_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM17
+#if defined(STM32_TIM17_IS_USED)
+#error "PWMD17 requires TIM17 but the timer is already used"
+#else
+#define STM32_TIM17_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM20
+#if defined(STM32_TIM20_IS_USED)
+#error "PWMD20 requires TIM20 but the timer is already used"
+#else
+#define STM32_TIM20_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM21
+#if defined(STM32_TIM21_IS_USED)
+#error "PWMD21 requires TIM21 but the timer is already used"
+#else
+#define STM32_TIM21_IS_USED
+#endif
+#endif
+
+#if STM32_PWM_USE_TIM22
+#if defined(STM32_TIM22_IS_USED)
+#error "PWMD22 requires TIM22 but the timer is already used"
+#else
+#define STM32_TIM22_IS_USED
+#endif
+#endif
+
+/* IRQ priority checks.*/
+#if STM32_PWM_USE_TIM1 && !defined(STM32_TIM1_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM1"
+#endif
+
+#if STM32_PWM_USE_TIM2 && !defined(STM32_TIM2_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM2"
+#endif
+
+#if STM32_PWM_USE_TIM3 && !defined(STM32_TIM3_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM3"
+#endif
+
+#if STM32_PWM_USE_TIM4 && !defined(STM32_TIM4_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM4"
+#endif
+
+#if STM32_PWM_USE_TIM5 && !defined(STM32_TIM5_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM5"
+#endif
+
+#if STM32_PWM_USE_TIM8 && !defined(STM32_TIM8_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM8_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM8"
+#endif
+
+#if STM32_PWM_USE_TIM9 && !defined(STM32_TIM9_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM9_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM9"
+#endif
+
+#if STM32_PWM_USE_TIM10 && !defined(STM32_TIM10_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM10_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM10"
+#endif
+
+#if STM32_PWM_USE_TIM11 && !defined(STM32_TIM11_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM11_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM11"
+#endif
+
+#if STM32_PWM_USE_TIM12 && !defined(STM32_TIM12_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM12_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM12"
+#endif
+
+#if STM32_PWM_USE_TIM13 && !defined(STM32_TIM13_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM13_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM13"
+#endif
+
+#if STM32_PWM_USE_TIM14 && !defined(STM32_TIM14_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM14_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM14"
+#endif
+
+#if STM32_PWM_USE_TIM15 && !defined(STM32_TIM15_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM15_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM15"
+#endif
+
+#if STM32_PWM_USE_TIM16 && !defined(STM32_TIM16_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM16_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM16"
+#endif
+
+#if STM32_PWM_USE_TIM17 && !defined(STM32_TIM17_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM17_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM17"
+#endif
+
+#if STM32_PWM_USE_TIM20 && !defined(STM32_TIM20_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM20_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM20"
+#endif
+
+#if STM32_PWM_USE_TIM21 && !defined(STM32_TIM21_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM21_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM21"
+#endif
+
+#if STM32_PWM_USE_TIM22 && !defined(STM32_TIM22_SUPPRESS_ISR) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_PWM_TIM22_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to TIM22"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a PWM mode.
+ */
+typedef uint32_t pwmmode_t;
+
+/**
+ * @brief Type of a PWM channel.
+ */
+typedef uint8_t pwmchannel_t;
+
+/**
+ * @brief Type of a channels mask.
+ */
+typedef uint32_t pwmchnmsk_t;
+
+/**
+ * @brief Type of a PWM counter.
+ */
+typedef uint32_t pwmcnt_t;
+
+/**
+ * @brief Type of a PWM driver channel configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Channel active logic level.
+ */
+ pwmmode_t mode;
+ /**
+ * @brief Channel callback pointer.
+ * @note This callback is invoked on the channel compare event. If set to
+ * @p NULL then the callback is disabled.
+ */
+ pwmcallback_t callback;
+ /* End of the mandatory fields.*/
+} PWMChannelConfig;
+
+/**
+ * @brief Type of a PWM driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ uint32_t frequency;
+ /**
+ * @brief PWM period in ticks.
+ * @note The low level can use assertions in order to catch invalid
+ * period specifications.
+ */
+ pwmcnt_t period;
+ /**
+ * @brief Periodic callback pointer.
+ * @note This callback is invoked on PWM counter reset. If set to
+ * @p NULL then the callback is disabled.
+ */
+ pwmcallback_t callback;
+ /**
+ * @brief Channels configurations.
+ */
+ PWMChannelConfig channels[PWM_CHANNELS];
+ /* End of the mandatory fields.*/
+ /**
+ * @brief TIM CR2 register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ */
+ uint32_t cr2;
+#if STM32_PWM_USE_ADVANCED || defined(__DOXYGEN__)
+ /**
+ * @brief TIM BDTR (break & dead-time) register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ */ \
+ uint32_t bdtr;
+#endif
+ /**
+ * @brief TIM DIER register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ * @note Only the DMA-related bits can be specified in this field.
+ */
+ uint32_t dier;
+} PWMConfig;
+
+/**
+ * @brief Structure representing a PWM driver.
+ */
+struct PWMDriver {
+ /**
+ * @brief Driver state.
+ */
+ pwmstate_t state;
+ /**
+ * @brief Current driver configuration data.
+ */
+ const PWMConfig *config;
+ /**
+ * @brief Current PWM period in ticks.
+ */
+ pwmcnt_t period;
+ /**
+ * @brief Mask of the enabled channels.
+ */
+ pwmchnmsk_t enabled;
+ /**
+ * @brief Number of channels in this instance.
+ */
+ pwmchannel_t channels;
+#if defined(PWM_DRIVER_EXT_FIELDS)
+ PWM_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
+ * @brief Pointer to the TIMx registers block.
+ */
+ stm32_tim_t *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Changes the period the PWM peripheral.
+ * @details This function changes the period of a PWM unit that has already
+ * been activated using @p pwmStart().
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The PWM unit period is changed to the new value.
+ * @note The function has effect at the next cycle start.
+ * @note If a period is specified that is shorter than the pulse width
+ * programmed in one of the channels then the behavior is not
+ * guaranteed.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] period new cycle time in ticks
+ *
+ * @notapi
+ */
+#define pwm_lld_change_period(pwmp, period) \
+ ((pwmp)->tim->ARR = ((period) - 1))
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_PWM_USE_TIM1 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD1;
+#endif
+
+#if STM32_PWM_USE_TIM2 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD2;
+#endif
+
+#if STM32_PWM_USE_TIM3 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD3;
+#endif
+
+#if STM32_PWM_USE_TIM4 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD4;
+#endif
+
+#if STM32_PWM_USE_TIM5 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD5;
+#endif
+
+#if STM32_PWM_USE_TIM8 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD8;
+#endif
+
+#if STM32_PWM_USE_TIM9 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD9;
+#endif
+
+#if STM32_PWM_USE_TIM10 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD10;
+#endif
+
+#if STM32_PWM_USE_TIM11 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD11;
+#endif
+
+#if STM32_PWM_USE_TIM12 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD12;
+#endif
+
+#if STM32_PWM_USE_TIM13 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD13;
+#endif
+
+#if STM32_PWM_USE_TIM14 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD14;
+#endif
+
+#if STM32_PWM_USE_TIM15 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD15;
+#endif
+
+#if STM32_PWM_USE_TIM16 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD16;
+#endif
+
+#if STM32_PWM_USE_TIM17 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD17;
+#endif
+
+#if STM32_PWM_USE_TIM20 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD20;
+#endif
+
+#if STM32_PWM_USE_TIM21 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD21;
+#endif
+
+#if STM32_PWM_USE_TIM22 && !defined(__DOXYGEN__)
+extern PWMDriver PWMD22;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void pwm_lld_init(void);
+ void pwm_lld_start(PWMDriver *pwmp);
+ void pwm_lld_stop(PWMDriver *pwmp);
+ void pwm_lld_enable_channel(PWMDriver *pwmp,
+ pwmchannel_t channel,
+ pwmcnt_t width);
+ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
+ void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
+ void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
+ void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel);
+ void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel);
+ void pwm_lld_serve_interrupt(PWMDriver *pwmp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PWM */
+
+#endif /* HAL_PWM_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c new file mode 100644 index 0000000..4c657b5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.c @@ -0,0 +1,492 @@ +/*
+ 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 TIMv1/hal_st_lld.c
+ * @brief ST Driver subsystem low level driver code.
+ *
+ * @addtogroup ST
+ * @{
+ */
+
+#include "hal.h"
+
+#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
+
+#if (OSAL_ST_RESOLUTION == 32)
+#define ST_ARR_INIT 0xFFFFFFFFU
+#else
+#define ST_ARR_INIT 0x0000FFFFU
+#endif
+
+#if STM32_ST_USE_TIMER == 2
+
+#if !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM2_IS_32BITS
+#error "TIM2 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM2_HANDLER
+#define ST_NUMBER STM32_TIM2_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM2(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM2_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM2_STOP
+#elif defined(STM32G0XX)
+#define ST_ENABLE_STOP() DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM2_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM2
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM2_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 3
+
+#if !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM3_IS_32BITS
+#error "TIM3 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM3_HANDLER
+#define ST_NUMBER STM32_TIM3_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM3(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM3_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM3_STOP
+#elif defined(STM32G0XX)
+#define ST_ENABLE_STOP() DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM3
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM3_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 4
+
+#if !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM4_IS_32BITS
+#error "TIM4 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM4_HANDLER
+#define ST_NUMBER STM32_TIM4_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM4(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM4_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM4_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM4
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM4_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 5
+
+#if !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM5_IS_32BITS
+#error "TIM5 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM5_HANDLER
+#define ST_NUMBER STM32_TIM5_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM5(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM5_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM5_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM5
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM5_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 9
+
+#if !STM32_HAS_TIM9
+#error "TIM9 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM9_IS_32BITS
+#error "TIM9 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM9_HANDLER
+#define ST_NUMBER STM32_TIM9_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK2
+#define ST_ENABLE_CLOCK() rccEnableTIM9(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM9_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB2FZR1 |= DBGMCU_APB2FZR1_DBG_TIM9_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB2LFZ1 |= DBGMCU_APB2LFZ1_DBG_TIM9
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM9_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 10
+
+#if !STM32_HAS_TIM10
+#error "TIM10 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM10_IS_32BITS
+#error "TIM10 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM10_HANDLER
+#define ST_NUMBER STM32_TIM10_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK2
+#define ST_ENABLE_CLOCK() rccEnableTIM10(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM10_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB2FZR1 |= DBGMCU_APB2FZR1_DBG_TIM10_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB2LFZ1 |= DBGMCU_APB2LFZ1_DBG_TIM10
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM10_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 11
+
+#if !STM32_HAS_TIM11
+#error "TIM11 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM11_IS_32BITS
+#error "TIM11 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM11_HANDLER
+#define ST_NUMBER STM32_TIM11_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK2
+#define ST_ENABLE_CLOCK() rccEnableTIM11(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM11_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB2FZR1 |= DBGMCU_APB2FZR1_DBG_TIM11_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB2LFZ1 |= DBGMCU_APB2LFZ1_DBG_TIM11
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM11_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 12
+
+#if !STM32_HAS_TIM12
+#error "TIM12 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM12_IS_32BITS
+#error "TIM12 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM12_HANDLER
+#define ST_NUMBER STM32_TIM12_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM12(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM12_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM12_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM12
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM12_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 13
+
+#if !STM32_HAS_TIM13
+#error "TIM13 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM13_IS_32BITS
+#error "TIM13 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM13_HANDLER
+#define ST_NUMBER STM32_TIM13_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM13(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM13_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM13_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM13
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM13_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 14
+
+#if !STM32_HAS_TIM14
+#error "TIM14 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM14_IS_32BITS
+#error "TIM14 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM14_HANDLER
+#define ST_NUMBER STM32_TIM14_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK1
+#define ST_ENABLE_CLOCK() rccEnableTIM14(true)
+#if defined(STM32F1XX)
+#define ST_ENABLE_STOP() DBGMCU->CR |= DBGMCU_CR_DBG_TIM14_STOP
+#elif defined(STM32L4XX) || defined(STM32L4XXP) || defined(STM32G4XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM14_STOP
+#elif defined(STM32H7XX)
+#define ST_ENABLE_STOP() DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM14
+#else
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM14_STOP
+#endif
+
+#elif STM32_ST_USE_TIMER == 21
+
+#if !STM32_HAS_TIM21
+#error "TIM21 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM21_IS_32BITS
+#error "TIM21 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM21_HANDLER
+#define ST_NUMBER STM32_TIM21_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK2
+#define ST_ENABLE_CLOCK() rccEnableTIM21(true)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB2_FZ_DBG_TIM21_STOP
+
+#elif STM32_ST_USE_TIMER == 22
+
+#if !STM32_HAS_TIM22
+#error "TIM22 not present in the selected device"
+#endif
+
+#if (OSAL_ST_RESOLUTION == 32) && !STM32_TIM22_IS_32BITS
+#error "TIM21 is not a 32bits timer"
+#endif
+
+#define ST_HANDLER STM32_TIM22_HANDLER
+#define ST_NUMBER STM32_TIM22_NUMBER
+#define ST_CLOCK_SRC STM32_TIMCLK2
+#define ST_ENABLE_CLOCK() rccEnableTIM22(true)
+#define ST_ENABLE_STOP() DBGMCU->APB1FZ |= DBGMCU_APB2_FZ_DBG_TIM21_STOP
+
+#else
+#error "STM32_ST_USE_TIMER specifies an unsupported timer"
+#endif
+
+#if ST_CLOCK_SRC % OSAL_ST_FREQUENCY != 0
+#error "the selected ST frequency is not obtainable because integer rounding"
+#endif
+
+#if (ST_CLOCK_SRC / OSAL_ST_FREQUENCY) - 1 > 0xFFFF
+#error "the selected ST frequency is not obtainable because TIM timer prescaler limits"
+#endif
+
+#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */
+
+#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC
+
+#define ST_HANDLER SysTick_Handler
+
+#if defined(STM32_CORE_CK)
+#define SYSTICK_CK STM32_CORE_CK
+#else
+#define SYSTICK_CK STM32_HCLK
+#endif
+
+#if SYSTICK_CK % OSAL_ST_FREQUENCY != 0
+#error "the selected ST frequency is not obtainable because integer rounding"
+#endif
+
+#if (SYSTICK_CK / OSAL_ST_FREQUENCY) - 1 > 0xFFFFFF
+#error "the selected ST frequency is not obtainable because SysTick timer counter limits"
+#endif
+
+#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if !defined(STM32_SYSTICK_SUPPRESS_ISR)
+/**
+ * @brief Interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(ST_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ st_lld_serve_interrupt();
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ST driver initialization.
+ *
+ * @notapi
+ */
+void st_lld_init(void) {
+
+#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
+ /* Free running counter mode.*/
+
+ /* Enabling timer clock.*/
+ ST_ENABLE_CLOCK();
+
+ /* Enabling the stop mode during debug for this timer.*/
+ ST_ENABLE_STOP();
+
+ /* Initializing the counter in free running mode.*/
+ STM32_ST_TIM->PSC = (ST_CLOCK_SRC / OSAL_ST_FREQUENCY) - 1;
+ STM32_ST_TIM->ARR = ST_ARR_INIT;
+ STM32_ST_TIM->CCMR1 = 0;
+ STM32_ST_TIM->CCR[0] = 0;
+#if ST_LLD_NUM_ALARMS > 1
+ STM32_ST_TIM->CCR[1] = 0;
+#endif
+#if ST_LLD_NUM_ALARMS > 2
+ STM32_ST_TIM->CCR[2] = 0;
+#endif
+#if ST_LLD_NUM_ALARMS > 3
+ STM32_ST_TIM->CCR[3] = 0;
+#endif
+ STM32_ST_TIM->DIER = 0;
+ STM32_ST_TIM->CR2 = 0;
+ STM32_ST_TIM->EGR = TIM_EGR_UG;
+ STM32_ST_TIM->CR1 = TIM_CR1_CEN;
+
+#if !defined(STM32_SYSTICK_SUPPRESS_ISR)
+ /* IRQ enabled.*/
+ nvicEnableVector(ST_NUMBER, STM32_ST_IRQ_PRIORITY);
+#endif
+#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */
+
+#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC
+ /* Periodic systick mode, the Cortex-Mx internal systick timer is used
+ in this mode.*/
+ SysTick->LOAD = (SYSTICK_CK / OSAL_ST_FREQUENCY) - 1;
+ SysTick->VAL = 0;
+ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
+ SysTick_CTRL_ENABLE_Msk |
+ SysTick_CTRL_TICKINT_Msk;
+
+ /* IRQ enabled.*/
+ nvicSetSystemHandlerPriority(HANDLER_SYSTICK, STM32_ST_IRQ_PRIORITY);
+#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */
+}
+
+/**
+ * @brief IRQ handling code.
+ */
+void st_lld_serve_interrupt(void) {
+#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
+ uint32_t sr;
+ stm32_tim_t *timp = STM32_ST_TIM;
+
+ sr = timp->SR;
+ sr &= timp->DIER & STM32_TIM_DIER_IRQ_MASK;
+ timp->SR = ~sr;
+
+ if ((sr & TIM_SR_CC1IF) != 0U)
+#endif
+ {
+ osalSysLockFromISR();
+ osalOsTimerHandlerI();
+ osalSysUnlockFromISR();
+ }
+#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
+#if ST_LLD_NUM_ALARMS > 1
+ if ((sr & TIM_SR_CC2IF) != 0U) {
+ if (st_callbacks[2] != NULL) {
+ st_callbacks[0](1U);
+ }
+ }
+#endif
+#if ST_LLD_NUM_ALARMS > 2
+ if ((sr & TIM_SR_CC3IF) != 0U) {
+ if (st_callbacks[2] != NULL) {
+ st_callbacks[1](2U);
+ }
+ }
+#endif
+#if ST_LLD_NUM_ALARMS > 3
+ if ((sr & TIM_SR_CC4IF) != 0U) {
+ if (st_callbacks[2] != NULL) {
+ st_callbacks[2](3U);
+ }
+ }
+#endif
+#endif
+}
+
+#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h new file mode 100644 index 0000000..2b7f537 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/hal_st_lld.h @@ -0,0 +1,701 @@ +/*
+ 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 TIMv1/hal_st_lld.h
+ * @brief ST Driver subsystem low level driver header.
+ * @details This header is designed to be include-able without having to
+ * include other files from the HAL.
+ *
+ * @addtogroup ST
+ * @{
+ */
+
+#ifndef HAL_ST_LLD_H
+#define HAL_ST_LLD_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/* Feature currently disabled.*/
+#define STM32_ST_ENFORCE_ALARMS 1
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SysTick timer IRQ priority.
+ */
+#if !defined(STM32_ST_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ST_IRQ_PRIORITY 8
+#endif
+
+/**
+ * @brief TIMx unit (by number) to be used for free running operations.
+ * @note You must select a 32 bits timer if a 32 bits @p systick_t type
+ * is required.
+ * @note Timers 2, 3, 4, 5, 21 and 22 are supported.
+ */
+#if !defined(STM32_ST_USE_TIMER) || defined(__DOXYGEN__)
+#define STM32_ST_USE_TIMER 2
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/* This has to go after transition to shared handlers is complete for all
+ platforms.*/
+#if !defined(STM32_HAS_TIM2)
+#define STM32_HAS_TIM2 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM3)
+#define STM32_HAS_TIM3 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM4)
+#define STM32_HAS_TIM4 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM5)
+#define STM32_HAS_TIM5 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM9)
+#define STM32_HAS_TIM9 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM10)
+#define STM32_HAS_TIM10 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM11)
+#define STM32_HAS_TIM11 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM12)
+#define STM32_HAS_TIM12 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM13)
+#define STM32_HAS_TIM13 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM14)
+#define STM32_HAS_TIM14 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM21)
+#define STM32_HAS_TIM21 FALSE
+#endif
+
+#if !defined(STM32_HAS_TIM22)
+#define STM32_HAS_TIM22 FALSE
+#endif
+/**/
+
+#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
+
+#if STM32_ST_USE_TIMER == 2
+
+#if defined(STM32_TIM2_IS_USED)
+#error "ST requires TIM2 but the timer is already used"
+#else
+#define STM32_TIM2_IS_USED
+#endif
+
+#if defined(STM32_TIM2_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM2
+#define ST_LLD_NUM_ALARMS STM32_TIM2_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 TRUE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 3
+
+#if defined(STM32_TIM3_IS_USED)
+#error "ST requires TIM3 but the timer is already used"
+#else
+#define STM32_TIM3_IS_USED
+#endif
+
+#if defined(STM32_TIM3_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM3
+#define ST_LLD_NUM_ALARMS STM32_TIM3_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 TRUE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 4
+
+#if defined(STM32_TIM4_IS_USED)
+#error "ST requires TIM4 but the timer is already used"
+#else
+#define STM32_TIM4_IS_USED
+#endif
+
+#if defined(STM32_TIM4_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM4
+#define ST_LLD_NUM_ALARMS STM32_TIM4_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 TRUE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 5
+
+#if defined(STM32_TIM5_IS_USED)
+#error "ST requires TIM5 but the timer is already used"
+#else
+#define STM32_TIM5_IS_USED
+#endif
+
+#if defined(STM32_TIM5_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM5
+#define ST_LLD_NUM_ALARMS STM32_TIM5_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 TRUE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 9
+
+#if defined(STM32_TIM9_IS_USED)
+#error "ST requires TIM9 but the timer is already used"
+#else
+#define STM32_TIM9_IS_USED
+#endif
+
+#if defined(STM32_TIM9_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM9
+#define ST_LLD_NUM_ALARMS STM32_TIM9_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 TRUE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 10
+
+#if defined(STM32_TIM10_IS_USED)
+#error "ST requires TIM10 but the timer is already used"
+#else
+#define STM32_TIM10_IS_USED
+#endif
+
+#if defined(STM32_TIM10_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM10
+#define ST_LLD_NUM_ALARMS STM32_TIM10_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 TRUE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 11
+
+#if defined(STM32_TIM11_IS_USED)
+#error "ST requires TIM11 but the timer is already used"
+#else
+#define STM32_TIM11_IS_USED
+#endif
+
+#if defined(STM32_TIM11_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM11
+#define ST_LLD_NUM_ALARMS STM32_TIM11_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 TRUE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 12
+
+#if defined(STM32_TIM12_IS_USED)
+#error "ST requires TIM12 but the timer is already used"
+#else
+#define STM32_TIM12_IS_USED
+#endif
+
+#if defined(STM32_TIM12_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM12
+#define ST_LLD_NUM_ALARMS STM32_TIM12_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 TRUE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 13
+
+#if defined(STM32_TIM13_IS_USED)
+#error "ST requires TIM13 but the timer is already used"
+#else
+#define STM32_TIM13_IS_USED
+#endif
+
+#if defined(STM32_TIM13_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM13
+#define ST_LLD_NUM_ALARMS STM32_TIM13_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 TRUE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 14
+
+#if defined(STM32_TIM14_IS_USED)
+#error "ST requires TIM14 but the timer is already used"
+#else
+#define STM32_TIM14_IS_USED
+#endif
+
+#if defined(STM32_TIM14_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM14
+#define ST_LLD_NUM_ALARMS STM32_TIM14_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 TRUE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 21
+
+#if defined(STM32_TIM21_IS_USED)
+#error "ST requires TIM21 but the timer is already used"
+#else
+#define STM32_TIM21_IS_USED
+#endif
+
+#if defined(STM32_TIM21_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM21
+#define ST_LLD_NUM_ALARMS STM32_TIM21_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 TRUE
+#define STM32_ST_USE_TIM22 FALSE
+
+#elif STM32_ST_USE_TIMER == 22
+
+#if defined(STM32_TIM22_IS_USED)
+#error "ST requires TIM22 but the timer is already used"
+#else
+#define STM32_TIM22_IS_USED
+#endif
+
+#if defined(STM32_TIM22_SUPPRESS_ISR)
+#define STM32_SYSTICK_SUPPRESS_ISR
+#endif
+
+#define STM32_ST_TIM STM32_TIM22
+#define ST_LLD_NUM_ALARMS STM32_TIM22_CHANNELS
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 TRUE
+
+#else
+#error "STM32_ST_USE_TIMER specifies an unsupported timer"
+#endif
+
+#if defined(STM32_ST_ENFORCE_ALARMS)
+
+#if (STM32_ST_ENFORCE_ALARMS < 1) || (STM32_ST_ENFORCE_ALARMS > ST_LLD_NUM_ALARMS)
+#error "invalid STM32_ST_ENFORCE_ALARMS value"
+#endif
+
+#undef ST_LLD_NUM_ALARMS
+#define ST_LLD_NUM_ALARMS STM32_ST_ENFORCE_ALARMS
+#endif
+
+#elif OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
+
+#define STM32_ST_USE_SYSTICK TRUE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#else
+
+#define STM32_ST_USE_SYSTICK FALSE
+#define STM32_ST_USE_TIM2 FALSE
+#define STM32_ST_USE_TIM3 FALSE
+#define STM32_ST_USE_TIM4 FALSE
+#define STM32_ST_USE_TIM5 FALSE
+#define STM32_ST_USE_TIM9 FALSE
+#define STM32_ST_USE_TIM10 FALSE
+#define STM32_ST_USE_TIM11 FALSE
+#define STM32_ST_USE_TIM12 FALSE
+#define STM32_ST_USE_TIM13 FALSE
+#define STM32_ST_USE_TIM14 FALSE
+#define STM32_ST_USE_TIM21 FALSE
+#define STM32_ST_USE_TIM22 FALSE
+
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void st_lld_init(void);
+ void st_lld_serve_interrupt(void);
+#ifdef __cplusplus
+}
+#endif
+
+/*===========================================================================*/
+/* Driver inline functions. */
+/*===========================================================================*/
+
+
+#if (OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) || defined(__DOXYGEN__)
+
+/**
+ * @brief Returns the time counter value.
+ *
+ * @return The counter value.
+ *
+ * @notapi
+ */
+static inline systime_t st_lld_get_counter(void) {
+
+ return (systime_t)STM32_ST_TIM->CNT;
+}
+
+/**
+ * @brief Starts the alarm.
+ * @note Makes sure that no spurious alarms are triggered after
+ * this call.
+ *
+ * @param[in] abstime the time to be set for the first alarm
+ *
+ * @notapi
+ */
+static inline void st_lld_start_alarm(systime_t abstime) {
+
+ STM32_ST_TIM->CCR[0] = (uint32_t)abstime;
+ STM32_ST_TIM->SR = 0;
+#if ST_LLD_NUM_ALARMS == 1
+ STM32_ST_TIM->DIER = STM32_TIM_DIER_CC1IE;
+#else
+ STM32_ST_TIM->DIER |= STM32_TIM_DIER_CC1IE;
+#endif
+}
+
+/**
+ * @brief Stops the alarm interrupt.
+ *
+ * @notapi
+ */
+static inline void st_lld_stop_alarm(void) {
+
+#if ST_LLD_NUM_ALARMS == 1
+ STM32_ST_TIM->DIER = 0U;
+#else
+ STM32_ST_TIM->DIER &= ~STM32_TIM_DIER_CC1IE;
+#endif
+}
+
+/**
+ * @brief Sets the alarm time.
+ *
+ * @param[in] abstime the time to be set for the next alarm
+ *
+ * @notapi
+ */
+static inline void st_lld_set_alarm(systime_t abstime) {
+
+ STM32_ST_TIM->CCR[0] = (uint32_t)abstime;
+}
+
+/**
+ * @brief Returns the current alarm time.
+ *
+ * @return The currently set alarm time.
+ *
+ * @notapi
+ */
+static inline systime_t st_lld_get_alarm(void) {
+
+ return (systime_t)STM32_ST_TIM->CCR[0];
+}
+
+/**
+ * @brief Determines if the alarm is active.
+ *
+ * @return The alarm status.
+ * @retval false if the alarm is not active.
+ * @retval true is the alarm is active
+ *
+ * @notapi
+ */
+static inline bool st_lld_is_alarm_active(void) {
+
+ return (bool)((STM32_ST_TIM->DIER & STM32_TIM_DIER_CC1IE) != 0);
+}
+
+#if (ST_LLD_NUM_ALARMS > 1) || defined(__DOXYGEN__)
+/**
+ * @brief Starts an alarm.
+ * @note Makes sure that no spurious alarms are triggered after
+ * this call.
+ * @note This functionality is only available in free running mode, the
+ * behavior in periodic mode is undefined.
+ *
+ * @param[in] abstime the time to be set for the first alarm
+ * @param[in] alarm alarm channel number
+ *
+ * @notapi
+ */
+static inline void st_lld_start_alarm_n(unsigned alarm, systime_t abstime) {
+
+
+ STM32_ST_TIM->CCR[alarm] = (uint32_t)abstime;
+ STM32_ST_TIM->SR = 0;
+ STM32_ST_TIM->DIER |= (STM32_TIM_DIER_CC1IE << alarm);
+}
+
+/**
+ * @brief Stops an alarm interrupt.
+ * @note This functionality is only available in free running mode, the
+ * behavior in periodic mode is undefined.
+ *
+ * @param[in] alarm alarm channel number
+ *
+ * @notapi
+ */
+static inline void st_lld_stop_alarm_n(unsigned alarm) {
+
+ STM32_ST_TIM->DIER &= ~(STM32_TIM_DIER_CC1IE << alarm);
+}
+
+/**
+ * @brief Sets an alarm time.
+ * @note This functionality is only available in free running mode, the
+ * behavior in periodic mode is undefined.
+ *
+ * @param[in] alarm alarm channel number
+ * @param[in] abstime the time to be set for the next alarm
+ *
+ * @notapi
+ */
+static inline void st_lld_set_alarm_n(unsigned alarm, systime_t abstime) {
+
+ STM32_ST_TIM->CCR[alarm] = (uint32_t)abstime;
+}
+
+/**
+ * @brief Returns an alarm current time.
+ * @note This functionality is only available in free running mode, the
+ * behavior in periodic mode is undefined.
+ *
+ * @param[in] alarm alarm channel number
+ * @return The currently set alarm time.
+ *
+ * @notapi
+ */
+static inline systime_t st_lld_get_alarm_n(unsigned alarm) {
+
+ return (systime_t)STM32_ST_TIM->CCR[alarm];
+}
+
+/**
+ * @brief Determines if an alarm is active.
+ *
+ * @param[in] alarm alarm channel number
+ * @return The alarm status.
+ * @retval false if the alarm is not active.
+ * @retval true is the alarm is active
+ *
+ * @notapi
+ */
+static inline bool st_lld_is_alarm_active_n(unsigned alarm) {
+
+ return (bool)((STM32_ST_TIM->DIER & (STM32_TIM_DIER_CC1IE << alarm)) != 0);
+}
+#endif /* ST_LLD_NUM_ALARMS > 1 */
+
+#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */
+
+#endif /* HAL_ST_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h new file mode 100644 index 0000000..8f158fe --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h @@ -0,0 +1,552 @@ +/*
+ 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 TIMv1/stm32_tim.h
+ * @brief STM32 TIM units common header.
+ * @note This file requires definitions from the ST STM32 header file.
+ *
+ * @addtogroup STM32_TIMv1
+ * @{
+ */
+
+#ifndef STM32_TIM_H
+#define STM32_TIM_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name TIM_CR1 register
+ * @{
+ */
+#define STM32_TIM_CR1_CEN (1U << 0)
+#define STM32_TIM_CR1_UDIS (1U << 1)
+#define STM32_TIM_CR1_URS (1U << 2)
+#define STM32_TIM_CR1_OPM (1U << 3)
+#define STM32_TIM_CR1_DIR (1U << 4)
+
+#define STM32_TIM_CR1_CMS_MASK (3U << 5)
+#define STM32_TIM_CR1_CMS(n) ((n) << 5)
+
+#define STM32_TIM_CR1_ARPE (1U << 7)
+
+#define STM32_TIM_CR1_CKD_MASK (3U << 8)
+#define STM32_TIM_CR1_CKD(n) ((n) << 8)
+
+#define STM32_TIM_CR1_UIFREMAP (1U << 11)
+/** @} */
+
+/**
+ * @name TIM_CR2 register
+ * @{
+ */
+#define STM32_TIM_CR2_CCPC (1U << 0)
+#define STM32_TIM_CR2_CCUS (1U << 2)
+#define STM32_TIM_CR2_CCDS (1U << 3)
+
+#define STM32_TIM_CR2_MMS_MASK (7U << 4)
+#define STM32_TIM_CR2_MMS(n) ((n) << 4)
+
+#define STM32_TIM_CR2_TI1S (1U << 7)
+#define STM32_TIM_CR2_OIS1 (1U << 8)
+#define STM32_TIM_CR2_OIS1N (1U << 9)
+#define STM32_TIM_CR2_OIS2 (1U << 10)
+#define STM32_TIM_CR2_OIS2N (1U << 11)
+#define STM32_TIM_CR2_OIS3 (1U << 12)
+#define STM32_TIM_CR2_OIS3N (1U << 13)
+#define STM32_TIM_CR2_OIS4 (1U << 14)
+#define STM32_TIM_CR2_OIS5 (1U << 16)
+#define STM32_TIM_CR2_OIS6 (1U << 18)
+
+#define STM32_TIM_CR2_MMS2_MASK (15U << 20)
+#define STM32_TIM_CR2_MMS2(n) ((n) << 20)
+/** @} */
+
+/**
+ * @name TIM_SMCR register
+ * @{
+ */
+#define STM32_TIM_SMCR_SMS_MASK ((7U << 0) | (1U << 16))
+#define STM32_TIM_SMCR_SMS(n) ((((n) & 7) << 0) | \
+ (((n) >> 3) << 16))
+
+#define STM32_TIM_SMCR_OCCS (1U << 3)
+
+#define STM32_TIM_SMCR_TS_MASK (7U << 4)
+#define STM32_TIM_SMCR_TS(n) ((n) << 4)
+
+#define STM32_TIM_SMCR_MSM (1U << 7)
+
+#define STM32_TIM_SMCR_ETF_MASK (15U << 8)
+#define STM32_TIM_SMCR_ETF(n) ((n) << 8)
+
+#define STM32_TIM_SMCR_ETPS_MASK (3U << 12)
+#define STM32_TIM_SMCR_ETPS(n) ((n) << 12)
+
+#define STM32_TIM_SMCR_ECE (1U << 14)
+#define STM32_TIM_SMCR_ETP (1U << 15)
+/** @} */
+
+/**
+ * @name TIM_DIER register
+ * @{
+ */
+#define STM32_TIM_DIER_UIE (1U << 0)
+#define STM32_TIM_DIER_CC1IE (1U << 1)
+#define STM32_TIM_DIER_CC2IE (1U << 2)
+#define STM32_TIM_DIER_CC3IE (1U << 3)
+#define STM32_TIM_DIER_CC4IE (1U << 4)
+#define STM32_TIM_DIER_COMIE (1U << 5)
+#define STM32_TIM_DIER_TIE (1U << 6)
+#define STM32_TIM_DIER_BIE (1U << 7)
+#define STM32_TIM_DIER_UDE (1U << 8)
+#define STM32_TIM_DIER_CC1DE (1U << 9)
+#define STM32_TIM_DIER_CC2DE (1U << 10)
+#define STM32_TIM_DIER_CC3DE (1U << 11)
+#define STM32_TIM_DIER_CC4DE (1U << 12)
+#define STM32_TIM_DIER_COMDE (1U << 13)
+#define STM32_TIM_DIER_TDE (1U << 14)
+
+#define STM32_TIM_DIER_IRQ_MASK (STM32_TIM_DIER_UIE | \
+ STM32_TIM_DIER_CC1IE | \
+ STM32_TIM_DIER_CC2IE | \
+ STM32_TIM_DIER_CC3IE | \
+ STM32_TIM_DIER_CC4IE | \
+ STM32_TIM_DIER_COMIE | \
+ STM32_TIM_DIER_TIE | \
+ STM32_TIM_DIER_BIE)
+
+/** @} */
+
+/**
+ * @name TIM_SR register
+ * @{
+ */
+#define STM32_TIM_SR_UIF (1U << 0)
+#define STM32_TIM_SR_CC1IF (1U << 1)
+#define STM32_TIM_SR_CC2IF (1U << 2)
+#define STM32_TIM_SR_CC3IF (1U << 3)
+#define STM32_TIM_SR_CC4IF (1U << 4)
+#define STM32_TIM_SR_COMIF (1U << 5)
+#define STM32_TIM_SR_TIF (1U << 6)
+#define STM32_TIM_SR_BIF (1U << 7)
+#define STM32_TIM_SR_B2IF (1U << 8)
+#define STM32_TIM_SR_CC1OF (1U << 9)
+#define STM32_TIM_SR_CC2OF (1U << 10)
+#define STM32_TIM_SR_CC3OF (1U << 11)
+#define STM32_TIM_SR_CC4OF (1U << 12)
+#define STM32_TIM_SR_CC5IF (1U << 16)
+#define STM32_TIM_SR_CC6IF (1U << 17)
+/** @} */
+
+/**
+ * @name TIM_EGR register
+ * @{
+ */
+#define STM32_TIM_EGR_UG (1U << 0)
+#define STM32_TIM_EGR_CC1G (1U << 1)
+#define STM32_TIM_EGR_CC2G (1U << 2)
+#define STM32_TIM_EGR_CC3G (1U << 3)
+#define STM32_TIM_EGR_CC4G (1U << 4)
+#define STM32_TIM_EGR_COMG (1U << 5)
+#define STM32_TIM_EGR_TG (1U << 6)
+#define STM32_TIM_EGR_BG (1U << 7)
+#define STM32_TIM_EGR_B2G (1U << 8)
+/** @} */
+
+/**
+ * @name TIM_CCMR1 register (output)
+ * @{
+ */
+#define STM32_TIM_CCMR1_CC1S_MASK (3U << 0)
+#define STM32_TIM_CCMR1_CC1S(n) ((n) << 0)
+
+#define STM32_TIM_CCMR1_OC1FE (1U << 2)
+#define STM32_TIM_CCMR1_OC1PE (1U << 3)
+
+#define STM32_TIM_CCMR1_OC1M_MASK ((7U << 4) | (1U << 16))
+#define STM32_TIM_CCMR1_OC1M(n) ((((n) & 7) << 4) | \
+ (((n) >> 3) << 16))
+
+#define STM32_TIM_CCMR1_OC1CE (1U << 7)
+
+#define STM32_TIM_CCMR1_CC2S_MASK (3U << 8)
+#define STM32_TIM_CCMR1_CC2S(n) ((n) << 8)
+
+#define STM32_TIM_CCMR1_OC2FE (1U << 10)
+#define STM32_TIM_CCMR1_OC2PE (1U << 11)
+
+#define STM32_TIM_CCMR1_OC2M_MASK ((7U << 12) | (1U << 24))
+#define STM32_TIM_CCMR1_OC2M(n) ((((n) & 7) << 12) | \
+ (((n) >> 3) << 24))
+
+#define STM32_TIM_CCMR1_OC2CE (1U << 15)
+/** @} */
+
+/**
+ * @name CCMR1 register (input)
+ * @{
+ */
+#define STM32_TIM_CCMR1_IC1PSC_MASK (3U << 2)
+#define STM32_TIM_CCMR1_IC1PSC(n) ((n) << 2)
+
+#define STM32_TIM_CCMR1_IC1F_MASK (15U << 4)
+#define STM32_TIM_CCMR1_IC1F(n) ((n) << 4)
+
+#define STM32_TIM_CCMR1_IC2PSC_MASK (3U << 10)
+#define STM32_TIM_CCMR1_IC2PSC(n) ((n) << 10)
+
+#define STM32_TIM_CCMR1_IC2F_MASK (15U << 12)
+#define STM32_TIM_CCMR1_IC2F(n) ((n) << 12)
+/** @} */
+
+/**
+ * @name TIM_CCMR2 register (output)
+ * @{
+ */
+#define STM32_TIM_CCMR2_CC3S_MASK (3U << 0)
+#define STM32_TIM_CCMR2_CC3S(n) ((n) << 0)
+
+#define STM32_TIM_CCMR2_OC3FE (1U << 2)
+#define STM32_TIM_CCMR2_OC3PE (1U << 3)
+
+#define STM32_TIM_CCMR2_OC3M_MASK ((7U << 4) | (1U << 16))
+#define STM32_TIM_CCMR2_OC3M(n) ((((n) & 7) << 4) | \
+ (((n) >> 3) << 16))
+
+#define STM32_TIM_CCMR2_OC3CE (1U << 7)
+
+#define STM32_TIM_CCMR2_CC4S_MASK (3U << 8)
+#define STM32_TIM_CCMR2_CC4S(n) ((n) << 8)
+
+#define STM32_TIM_CCMR2_OC4FE (1U << 10)
+#define STM32_TIM_CCMR2_OC4PE (1U << 11)
+
+#define STM32_TIM_CCMR2_OC4M_MASK ((7U << 12) | (1U << 24))
+#define STM32_TIM_CCMR2_OC4M(n) ((((n) & 7) << 12) | \
+ (((n) >> 3) << 24))
+
+#define STM32_TIM_CCMR2_OC4CE (1U << 15)
+/** @} */
+
+/**
+ * @name TIM_CCMR2 register (input)
+ * @{
+ */
+#define STM32_TIM_CCMR2_IC3PSC_MASK (3U << 2)
+#define STM32_TIM_CCMR2_IC3PSC(n) ((n) << 2)
+
+#define STM32_TIM_CCMR2_IC3F_MASK (15U << 4)
+#define STM32_TIM_CCMR2_IC3F(n) ((n) << 4)
+
+#define STM32_TIM_CCMR2_IC4PSC_MASK (3U << 10)
+#define STM32_TIM_CCMR2_IC4PSC(n) ((n) << 10)
+
+#define STM32_TIM_CCMR2_IC4F_MASK (15U << 12)
+#define STM32_TIM_CCMR2_IC4F(n) ((n) << 12)
+/** @} */
+
+/**
+ * @name TIM_CCER register
+ * @{
+ */
+#define STM32_TIM_CCER_CC1E (1U << 0)
+#define STM32_TIM_CCER_CC1P (1U << 1)
+#define STM32_TIM_CCER_CC1NE (1U << 2)
+#define STM32_TIM_CCER_CC1NP (1U << 3)
+#define STM32_TIM_CCER_CC2E (1U << 4)
+#define STM32_TIM_CCER_CC2P (1U << 5)
+#define STM32_TIM_CCER_CC2NE (1U << 6)
+#define STM32_TIM_CCER_CC2NP (1U << 7)
+#define STM32_TIM_CCER_CC3E (1U << 8)
+#define STM32_TIM_CCER_CC3P (1U << 9)
+#define STM32_TIM_CCER_CC3NE (1U << 10)
+#define STM32_TIM_CCER_CC3NP (1U << 11)
+#define STM32_TIM_CCER_CC4E (1U << 12)
+#define STM32_TIM_CCER_CC4P (1U << 13)
+#define STM32_TIM_CCER_CC4NE (1U << 14)
+#define STM32_TIM_CCER_CC4NP (1U << 15)
+#define STM32_TIM_CCER_CC5E (1U << 16)
+#define STM32_TIM_CCER_CC5P (1U << 17)
+#define STM32_TIM_CCER_CC6E (1U << 20)
+#define STM32_TIM_CCER_CC6P (1U << 21)
+/** @} */
+
+/**
+ * @name TIM_CNT register
+ * @{
+ */
+#define STM32_TIM_CNT_UIFCPY (1U << 31)
+/** @} */
+
+/**
+ * @name TIM_BDTR register
+ * @{
+ */
+#define STM32_TIM_BDTR_DTG_MASK (255U << 0)
+#define STM32_TIM_BDTR_DTG(n) ((n) << 0)
+
+#define STM32_TIM_BDTR_LOCK_MASK (3U << 8)
+#define STM32_TIM_BDTR_LOCK(n) ((n) << 8)
+
+#define STM32_TIM_BDTR_OSSI (1U << 10)
+#define STM32_TIM_BDTR_OSSR (1U << 11)
+#define STM32_TIM_BDTR_BKE (1U << 12)
+#define STM32_TIM_BDTR_BKP (1U << 13)
+#define STM32_TIM_BDTR_AOE (1U << 14)
+#define STM32_TIM_BDTR_MOE (1U << 15)
+
+#define STM32_TIM_BDTR_BKF_MASK (15U << 16)
+#define STM32_TIM_BDTR_BKF(n) ((n) << 16)
+#define STM32_TIM_BDTR_BK2F_MASK (15U << 20)
+#define STM32_TIM_BDTR_BK2F(n) ((n) << 20)
+
+#define STM32_TIM_BDTR_BK2E (1U << 24)
+#define STM32_TIM_BDTR_BK2P (1U << 25)
+/** @} */
+
+/**
+ * @name TIM_DCR register
+ * @{
+ */
+#define STM32_TIM_DCR_DBA_MASK (31U << 0)
+#define STM32_TIM_DCR_DBA(n) ((n) << 0)
+
+#define STM32_TIM_DCR_DBL_MASK (31U << 8)
+#define STM32_TIM_DCR_DBL(n) ((n) << 8)
+/** @} */
+
+/**
+ * @name TIM16_OR register
+ * @{
+ */
+#define STM32_TIM16_OR_TI1_RMP_MASK (3U << 6)
+#define STM32_TIM16_OR_TI1_RMP(n) ((n) << 6)
+/** @} */
+
+/**
+ * @name TIM_OR register
+ * @{
+ */
+#define STM32_TIM_OR_ETR_RMP_MASK (15U << 0)
+#define STM32_TIM_OR_ETR_RMP(n) ((n) << 0)
+/** @} */
+
+/**
+ * @name TIM_CCMR3 register
+ * @{
+ */
+#define STM32_TIM_CCMR3_OC5FE (1U << 2)
+#define STM32_TIM_CCMR3_OC5PE (1U << 3)
+
+#define STM32_TIM_CCMR3_OC5M_MASK ((7U << 4) | (1U << 16))
+#define STM32_TIM_CCMR3_OC5M(n) ((((n) & 7) << 4) | \
+ (((n) >> 2) << 16))
+
+#define STM32_TIM_CCMR3_OC5CE (1U << 7)
+
+#define STM32_TIM_CCMR3_OC6FE (1U << 10)
+#define STM32_TIM_CCMR3_OC6PE (1U << 11)
+
+#define STM32_TIM_CCMR3_OC6M_MASK ((7U << 12) | (1U << 24))
+#define STM32_TIM_CCMR3_OC6M(n) ((((n) & 7) << 12) | \
+ (((n) >> 2) << 24))
+
+#define STM32_TIM_CCMR3_OC6CE (1U << 15)
+/** @} */
+
+/**
+ * @name LPTIM_ISR register
+ * @{
+ */
+#define STM32_LPTIM_ISR_CMPM (1U << 0)
+#define STM32_LPTIM_ISR_ARRM (1U << 1)
+#define STM32_LPTIM_ISR_EXTTRIG (1U << 2)
+#define STM32_LPTIM_ISR_CMPOK (1U << 3)
+#define STM32_LPTIM_ISR_ARROK (1U << 4)
+#define STM32_LPTIM_ISR_UP (1U << 5)
+#define STM32_LPTIM_ISR_DOWN (1U << 6)
+/** @} */
+
+/**
+ * @name LPTIM_ICR register
+ * @{
+ */
+#define STM32_LPTIM_ICR_CMPMCF (1U << 0)
+#define STM32_LPTIM_ICR_ARRMCF (1U << 1)
+#define STM32_LPTIM_ICR_EXTTRIGCF (1U << 2)
+#define STM32_LPTIM_ICR_CMPOKCF (1U << 3)
+#define STM32_LPTIM_ICR_ARROKCF (1U << 4)
+#define STM32_LPTIM_ICR_UPCF (1U << 5)
+#define STM32_LPTIM_ICR_DOWNCF (1U << 6)
+/** @} */
+
+/**
+ * @name LPTIM_IER register
+ * @{
+ */
+#define STM32_LPTIM_IER_CMPMIE (1U << 0)
+#define STM32_LPTIM_IER_ARRMIE (1U << 1)
+#define STM32_LPTIM_IER_EXTTRIGIE (1U << 2)
+#define STM32_LPTIM_IER_CMPOKIE (1U << 3)
+#define STM32_LPTIM_IER_ARROKIE (1U << 4)
+#define STM32_LPTIM_IER_UPIE (1U << 5)
+#define STM32_LPTIM_IER_DOWNIE (1U << 6)
+/** @} */
+
+/**
+ * @name LPTIM_CFGR register
+ * @{
+ */
+#define STM32_LPTIM_CFGR_CKSEL (1U << 0)
+#define STM32_LPTIM_CFGR_CKPOL_MASK (3U << 1)
+#define STM32_LPTIM_CFGR_CKPOL(n) ((n) << 1)
+#define STM32_LPTIM_CFGR_CKFLT_MASK (3U << 3)
+#define STM32_LPTIM_CFGR_CKFLT(n) ((n) << 3)
+#define STM32_LPTIM_CFGR_TRGFLT_MASK (3U << 6)
+#define STM32_LPTIM_CFGR_TRGFLT(n) ((n) << 6)
+#define STM32_LPTIM_CFGR_PRESC_MASK (7U << 9)
+#define STM32_LPTIM_CFGR_PRESC(n) ((n) << 9)
+#define STM32_LPTIM_CFGR_TRIGSEL_MASK (7U << 13)
+#define STM32_LPTIM_CFGR_TRIGSEL(n) ((n) << 13)
+#define STM32_LPTIM_CFGR_TRIGEN_MASK (3U << 17)
+#define STM32_LPTIM_CFGR_TRIGEN(n) ((n) << 17)
+#define STM32_LPTIM_CFGR_TIMOUT (1U << 19)
+#define STM32_LPTIM_CFGR_WAVE (1U << 20)
+#define STM32_LPTIM_CFGR_WAVPOL (1U << 21)
+#define STM32_LPTIM_CFGR_PRELOAD (1U << 22)
+#define STM32_LPTIM_CFGR_COUNTMODE (1U << 23)
+#define STM32_LPTIM_CFGR_ENC (1U << 24)
+/** @} */
+
+/**
+ * @name LPTIM_CR register
+ * @{
+ */
+#define STM32_LPTIM_CR_ENABLE (1U << 0)
+#define STM32_LPTIM_CR_SNGSTRT (1U << 1)
+#define STM32_LPTIM_CR_CNTSTRT (1U << 2)
+/** @} */
+
+/**
+ * @name LPTIM_OR register
+ * @{
+ */
+#define STM32_LPTIM_OR_0 (1U << 0)
+#define STM32_LPTIM_OR_1 (1U << 1)
+/** @} */
+
+/**
+ * @name TIM units references
+ * @{
+ */
+#define STM32_TIM1 ((stm32_tim_t *)TIM1_BASE)
+#define STM32_TIM2 ((stm32_tim_t *)TIM2_BASE)
+#define STM32_TIM3 ((stm32_tim_t *)TIM3_BASE)
+#define STM32_TIM4 ((stm32_tim_t *)TIM4_BASE)
+#define STM32_TIM5 ((stm32_tim_t *)TIM5_BASE)
+#define STM32_TIM6 ((stm32_tim_t *)TIM6_BASE)
+#define STM32_TIM7 ((stm32_tim_t *)TIM7_BASE)
+#define STM32_TIM8 ((stm32_tim_t *)TIM8_BASE)
+#define STM32_TIM9 ((stm32_tim_t *)TIM9_BASE)
+#define STM32_TIM10 ((stm32_tim_t *)TIM10_BASE)
+#define STM32_TIM11 ((stm32_tim_t *)TIM11_BASE)
+#define STM32_TIM12 ((stm32_tim_t *)TIM12_BASE)
+#define STM32_TIM13 ((stm32_tim_t *)TIM13_BASE)
+#define STM32_TIM14 ((stm32_tim_t *)TIM14_BASE)
+#define STM32_TIM15 ((stm32_tim_t *)TIM15_BASE)
+#define STM32_TIM16 ((stm32_tim_t *)TIM16_BASE)
+#define STM32_TIM17 ((stm32_tim_t *)TIM17_BASE)
+#define STM32_TIM18 ((stm32_tim_t *)TIM18_BASE)
+#define STM32_TIM19 ((stm32_tim_t *)TIM19_BASE)
+#define STM32_TIM20 ((stm32_tim_t *)TIM20_BASE)
+#define STM32_TIM21 ((stm32_tim_t *)TIM21_BASE)
+#define STM32_TIM22 ((stm32_tim_t *)TIM22_BASE)
+
+#define STM32_LPTIM1 ((stm32_lptim_t *)LPTIM1_BASE)
+#define STM32_LPTIM2 ((stm32_lptim_t *)LPTIM2_BASE)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 TIM registers block.
+ * @note This is the most general known form, not all timers have
+ * necessarily all registers and bits.
+ */
+typedef struct {
+ volatile uint32_t CR1;
+ volatile uint32_t CR2;
+ volatile uint32_t SMCR;
+ volatile uint32_t DIER;
+ volatile uint32_t SR;
+ volatile uint32_t EGR;
+ volatile uint32_t CCMR1;
+ volatile uint32_t CCMR2;
+ volatile uint32_t CCER;
+ volatile uint32_t CNT;
+ volatile uint32_t PSC;
+ volatile uint32_t ARR;
+ volatile uint32_t RCR;
+ volatile uint32_t CCR[4];
+ volatile uint32_t BDTR;
+ volatile uint32_t DCR;
+ volatile uint32_t DMAR;
+ volatile uint32_t OR;
+ volatile uint32_t CCMR3;
+ volatile uint32_t CCXR[2];
+} stm32_tim_t;
+
+/**
+ * @brief STM32 LPTIM registers block.
+ * @note This is the most general known form, not all timers have
+ * necessarily all registers and bits.
+ */
+typedef struct {
+ volatile uint32_t ISR;
+ volatile uint32_t ICR;
+ volatile uint32_t IER;
+ volatile uint32_t CFGR;
+ volatile uint32_t CR;
+ volatile uint32_t CMP;
+ volatile uint32_t ARR;
+ volatile uint32_t CNT;
+ volatile uint32_t OR;
+} stm32_lptim_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#endif /* STM32_TIM_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc new file mode 100644 index 0000000..eebaa8b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1.inc @@ -0,0 +1,172 @@ +/* + 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 TIMv1/stm32_tim1_tim15_tim16_tim17.inc + * @brief Shared TIM1 handler. + * + * @addtogroup STM32_TIM1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM1) +#error "STM32_HAS_TIM1 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM1) +#define STM32_GPT_USE_TIM1 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM1) +#define STM32_ICU_USE_TIM1 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM1) +#define STM32_PWM_USE_TIM1 FALSE +#endif +#if !defined(STM32_ST_USE_TIM1) +#define STM32_ST_USE_TIM1 FALSE +#endif + +#if STM32_HAS_TIM1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM1_UP_PRIORITY) +#error "STM32_IRQ_TIM1_UP_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_CC_PRIORITY) +#error "STM32_IRQ_TIM1_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_UP_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_UP_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM1 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim1_irq_init(void) { +#if defined(STM32_TIM1_IS_USED) + nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_IRQ_TIM1_UP_PRIORITY); + nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_IRQ_TIM1_CC_PRIORITY); +#endif +} + +static inline void tim1_irq_deinit(void) { +#if defined(STM32_TIM1_IS_USED) + nvicDisableVector(STM32_TIM1_UP_NUMBER); + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM1_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM1-UP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM1 + gpt_lld_serve_interrupt(&GPTD1); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM1 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief TIM1-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc new file mode 100644 index 0000000..920af71 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim14.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim14.inc + * @brief Shared TIM14 handler. + * + * @addtogroup STM32_TIM14_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM14) +#error "STM32_HAS_TIM14 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM14) +#define STM32_GPT_USE_TIM14 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM14) +#define STM32_ICU_USE_TIM14 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM14) +#define STM32_PWM_USE_TIM14 FALSE +#endif +#if !defined(STM32_ST_USE_TIM14) +#define STM32_ST_USE_TIM14 FALSE +#endif + +#if STM32_HAS_TIM14 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM14_PRIORITY) +#error "STM32_IRQ_TIM14_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM14_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM14_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM14 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim14_irq_init(void) { +#if defined(STM32_TIM14_IS_USED) + nvicEnableVector(STM32_TIM14_NUMBER, STM32_IRQ_TIM14_PRIORITY); +#endif +} + +static inline void tim14_irq_deinit(void) { +#if defined(STM32_TIM14_IS_USED) + nvicDisableVector(STM32_TIM14_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM14_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM14 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM14_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM14 + gpt_lld_serve_interrupt(&GPTD14); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM14 + icu_lld_serve_interrupt(&ICUD14); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM14 + pwm_lld_serve_interrupt(&PWMD14); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM14 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc new file mode 100644 index 0000000..da90531 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim15.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim15.inc + * @brief Shared TIM15 handler. + * + * @addtogroup STM32_TIM15_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM15) +#error "STM32_HAS_TIM15 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM15) +#define STM32_GPT_USE_TIM15 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM15) +#define STM32_ICU_USE_TIM15 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM15) +#define STM32_PWM_USE_TIM15 FALSE +#endif +#if !defined(STM32_ST_USE_TIM15) +#define STM32_ST_USE_TIM15 FALSE +#endif + +#if STM32_HAS_TIM15 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM15_PRIORITY) +#error "STM32_IRQ_TIM15_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM15_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM15 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim15_irq_init(void) { +#if defined(STM32_TIM15_IS_USED) + nvicEnableVector(STM32_TIM15_NUMBER, STM32_IRQ_TIM15_PRIORITY); +#endif +} + +static inline void tim15_irq_deinit(void) { +#if defined(STM32_TIM15_IS_USED) + nvicDisableVector(STM32_TIM15_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM15_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM15 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM15_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM15 + gpt_lld_serve_interrupt(&GPTD15); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM15 + icu_lld_serve_interrupt(&ICUD15); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM15 + pwm_lld_serve_interrupt(&PWMD15); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM15 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc new file mode 100644 index 0000000..56517b1 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim16.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim16.inc + * @brief Shared TIM16 handler. + * + * @addtogroup STM32_TIM16_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM16) +#error "STM32_HAS_TIM16 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM16) +#define STM32_GPT_USE_TIM16 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM16) +#define STM32_ICU_USE_TIM16 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM16) +#define STM32_PWM_USE_TIM16 FALSE +#endif +#if !defined(STM32_ST_USE_TIM16) +#define STM32_ST_USE_TIM16 FALSE +#endif + +#if STM32_HAS_TIM16 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM16_PRIORITY) +#error "STM32_IRQ_TIM16_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM16_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM16_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM16 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim16_irq_init(void) { +#if defined(STM32_TIM16_IS_USED) + nvicEnableVector(STM32_TIM16_NUMBER, STM32_IRQ_TIM16_PRIORITY); +#endif +} + +static inline void tim16_irq_deinit(void) { +#if defined(STM32_TIM16_IS_USED) + nvicDisableVector(STM32_TIM16_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM16_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM16 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM16_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM16 + gpt_lld_serve_interrupt(&GPTD16); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM16 + icu_lld_serve_interrupt(&ICUD16); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM16 + pwm_lld_serve_interrupt(&PWMD16); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM16 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc new file mode 100644 index 0000000..eb6725b --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim17.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim17.inc + * @brief Shared TIM17 handler. + * + * @addtogroup STM32_TIM17_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM17) +#error "STM32_HAS_TIM17 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM17) +#define STM32_GPT_USE_TIM17 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM17) +#define STM32_ICU_USE_TIM17 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM17) +#define STM32_PWM_USE_TIM17 FALSE +#endif +#if !defined(STM32_ST_USE_TIM17) +#define STM32_ST_USE_TIM17 FALSE +#endif + +#if STM32_HAS_TIM17 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM17_PRIORITY) +#error "STM32_IRQ_TIM17_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM17_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM17_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM17 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim17_irq_init(void) { +#if defined(STM32_TIM17_IS_USED) + nvicEnableVector(STM32_TIM17_NUMBER, STM32_IRQ_TIM17_PRIORITY); +#endif +} + +static inline void tim17_irq_deinit(void) { +#if defined(STM32_TIM17_IS_USED) + nvicDisableVector(STM32_TIM17_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM17_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM17 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM17_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM17 + gpt_lld_serve_interrupt(&GPTD17); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM17 + icu_lld_serve_interrupt(&ICUD17); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM17 + pwm_lld_serve_interrupt(&PWMD17); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM17 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc new file mode 100644 index 0000000..c40da37 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_15_16_17.inc @@ -0,0 +1,341 @@ +/* + 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 TIMv1/stm32_tim1_15_16_17.inc + * @brief Shared TIM1, TIM15, TIM16, TIM17 handler. + * + * @addtogroup STM32_TIM1_TIM15_TIM16_TIM17_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM1) +#error "STM32_HAS_TIM1 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM15) +#error "STM32_HAS_TIM15 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM16) +#error "STM32_HAS_TIM16 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM17) +#error "STM32_HAS_TIM17 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM1) +#define STM32_GPT_USE_TIM1 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM1) +#define STM32_ICU_USE_TIM1 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM1) +#define STM32_PWM_USE_TIM1 FALSE +#endif +#if !defined(STM32_ST_USE_TIM1) +#define STM32_ST_USE_TIM1 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM15) +#define STM32_GPT_USE_TIM15 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM15) +#define STM32_ICU_USE_TIM15 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM15) +#define STM32_PWM_USE_TIM15 FALSE +#endif +#if !defined(STM32_ST_USE_TIM15) +#define STM32_ST_USE_TIM15 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM16) +#define STM32_GPT_USE_TIM16 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM16) +#define STM32_ICU_USE_TIM16 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM16) +#define STM32_PWM_USE_TIM16 FALSE +#endif +#if !defined(STM32_ST_USE_TIM16) +#define STM32_ST_USE_TIM16 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM17) +#define STM32_GPT_USE_TIM17 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM17) +#define STM32_ICU_USE_TIM17 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM17) +#define STM32_PWM_USE_TIM17 FALSE +#endif +#if !defined(STM32_ST_USE_TIM17) +#define STM32_ST_USE_TIM17 FALSE +#endif + +#if STM32_HAS_TIM1 || STM32_HAS_TIM15 || STM32_HAS_TIM16 || STM32_HAS_TIM17 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM1_BRK_TIM15_PRIORITY) +#error "STM32_IRQ_TIM1_BRK_TIM15_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_UP_TIM16_PRIORITY) +#error "STM32_IRQ_TIM1_UP_TIM16_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY) +#error "STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_CC_PRIORITY) +#error "STM32_IRQ_TIM1_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_BRK_TIM15_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_BRK_TIM15_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_UP_TIM16_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_UP_TIM16_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM1 || STM32_HAS_TIM15 || STM32_HAS_TIM16 || STM32_HAS_TIM17 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim1_tim15_tim16_tim17_irq_init(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM15_IS_USED) + nvicEnableVector(STM32_TIM1_BRK_TIM15_NUMBER, + STM32_IRQ_TIM1_BRK_TIM15_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM16_IS_USED) + nvicEnableVector(STM32_TIM1_UP_TIM16_NUMBER, + STM32_IRQ_TIM1_UP_TIM16_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM17_IS_USED) + nvicEnableVector(STM32_TIM1_TRGCO_TIM17_NUMBER, + STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicEnableVector(STM32_TIM1_CC_NUMBER, + STM32_IRQ_TIM1_CC_PRIORITY); +#endif +} + +static inline void tim1_tim15_tim16_tim17_irq_deinit(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM15_IS_USED) + nvicDisableVector(STM32_TIM1_BRK_TIM15_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM16_IS_USED) + nvicDisableVector(STM32_TIM1_UP_TIM16_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM17_IS_USED) + nvicDisableVector(STM32_TIM1_TRGCO_TIM17_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM15_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-BRK, TIM15 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_BRK_TIM15_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM15 + gpt_lld_serve_interrupt(&GPTD15); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM15 + icu_lld_serve_interrupt(&ICUD15); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM15 + pwm_lld_serve_interrupt(&PWMD15); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM15 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM16_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-UP, TIM16 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_TIM16_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM1 + gpt_lld_serve_interrupt(&GPTD1); +#endif +#if STM32_GPT_USE_TIM16 + gpt_lld_serve_interrupt(&GPTD16); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#if STM32_PWM_USE_TIM16 + pwm_lld_serve_interrupt(&PWMD16); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM1 + st_lld_serve_interrupt(); +#endif +#if STM32_ST_USE_TIM16 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM17_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-TRG-COM, TIM17 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_TRGCO_TIM17_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM17 + gpt_lld_serve_interrupt(&GPTD17); +#endif +#endif +#if HAL_USE_ICU + /* Not used by ICU.*/ +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM17 + pwm_lld_serve_interrupt(&PWMD17); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM17 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM1-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc new file mode 100644 index 0000000..bebcf54 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim1_9_10_11.inc @@ -0,0 +1,343 @@ +/* + 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 TIMv1/stm32_tim1_9_10_11.inc + * @brief Shared TIM1, TIM9, TIM10, TIM11 handler. + * + * @addtogroup STM32_TIM1_TIM9_TIM10_TIM11_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM1) +#error "STM32_HAS_TIM1 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM9) +#error "STM32_HAS_TIM9 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM10) +#error "STM32_HAS_TIM10 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM11) +#error "STM32_HAS_TIM11 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM1) +#define STM32_GPT_USE_TIM1 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM1) +#define STM32_ICU_USE_TIM1 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM1) +#define STM32_PWM_USE_TIM1 FALSE +#endif +#if !defined(STM32_ST_USE_TIM1) +#define STM32_ST_USE_TIM1 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM9) +#define STM32_GPT_USE_TIM9 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM9) +#define STM32_ICU_USE_TIM9 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM9) +#define STM32_PWM_USE_TIM9 FALSE +#endif +#if !defined(STM32_ST_USE_TIM9) +#define STM32_ST_USE_TIM9 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM10) +#define STM32_GPT_USE_TIM10 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM10) +#define STM32_ICU_USE_TIM10 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM10) +#define STM32_PWM_USE_TIM10 FALSE +#endif +#if !defined(STM32_ST_USE_TIM10) +#define STM32_ST_USE_TIM10 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM11) +#define STM32_GPT_USE_TIM11 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM11) +#define STM32_ICU_USE_TIM11 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM11) +#define STM32_PWM_USE_TIM11 FALSE +#endif +#if !defined(STM32_ST_USE_TIM11) +#define STM32_ST_USE_TIM11 FALSE +#endif + +#if STM32_HAS_TIM1 || STM32_HAS_TIM9 || STM32_HAS_TIM10 || STM32_HAS_TIM11 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM1_BRK_TIM9_PRIORITY) +#error "STM32_IRQ_TIM1_BRK_TIM9_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_UP_TIM10_PRIORITY) +#error "STM32_IRQ_TIM1_UP_TIM10_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY) +#error "STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM1_CC_PRIORITY) +#error "STM32_IRQ_TIM1_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_BRK_TIM9_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_BRK_TIM9_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_UP_TIM10_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_UP_TIM10_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM1_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM1_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM1 || STM32_HAS_TIM9 || STM32_HAS_TIM10 || STM32_HAS_TIM11 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim1_tim9_tim10_tim11_irq_init(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM9_IS_USED) + nvicEnableVector(STM32_TIM1_BRK_TIM9_NUMBER, + STM32_IRQ_TIM1_BRK_TIM9_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM10_IS_USED) + nvicEnableVector(STM32_TIM1_UP_TIM10_NUMBER, + STM32_IRQ_TIM1_UP_TIM10_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM11_IS_USED) + nvicEnableVector(STM32_TIM1_TRGCO_TIM11_NUMBER, + STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicEnableVector(STM32_TIM1_CC_NUMBER, + STM32_IRQ_TIM1_CC_PRIORITY); +#endif +} + +static inline void tim1_tim9_tim10_tim11_irq_deinit(void) { +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM9_IS_USED) + nvicDisableVector(STM32_TIM1_BRK_TIM9_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM10_IS_USED) + nvicDisableVector(STM32_TIM1_UP_TIM10_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM11_IS_USED) + nvicDisableVector(STM32_TIM1_TRGCO_TIM11_NUMBER); +#endif +#if defined(STM32_TIM1_IS_USED) + nvicDisableVector(STM32_TIM1_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM19_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-BRK, TIM9 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_BRK_TIM9_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM9 + gpt_lld_serve_interrupt(&GPTD9); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM9 + icu_lld_serve_interrupt(&ICUD9); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM9 + pwm_lld_serve_interrupt(&PWMD9); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM9 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM10_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-UP, TIM10 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_UP_TIM10_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM1 + gpt_lld_serve_interrupt(&GPTD1); +#endif +#if STM32_GPT_USE_TIM10 + gpt_lld_serve_interrupt(&GPTD10); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#if STM32_ICU_USE_TIM10 + icu_lld_serve_interrupt(&ICUD10); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#if STM32_PWM_USE_TIM10 + pwm_lld_serve_interrupt(&PWMD10); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM1 + st_lld_serve_interrupt(); +#endif +#if STM32_ST_USE_TIM10 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) || defined(STM32_TIM11_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM1-TRG-COM, TIM11 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_TRGCO_TIM11_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM11 + gpt_lld_serve_interrupt(&GPTD11); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM11 + icu_lld_serve_interrupt(&ICUD11); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM11 + pwm_lld_serve_interrupt(&PWMD11); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM11 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM1_IS_USED) +/** + * @brief TIM1-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM1 + icu_lld_serve_interrupt(&ICUD1); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM1 + pwm_lld_serve_interrupt(&PWMD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc new file mode 100644 index 0000000..435deae --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim2.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim2.inc + * @brief Shared TIM2 handler. + * + * @addtogroup STM32_TIM2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM2) +#error "STM32_HAS_TIM2 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM2) +#define STM32_GPT_USE_TIM2 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM2) +#define STM32_ICU_USE_TIM2 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM2) +#define STM32_PWM_USE_TIM2 FALSE +#endif +#if !defined(STM32_ST_USE_TIM2) +#define STM32_ST_USE_TIM2 FALSE +#endif + +#if STM32_HAS_TIM2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM2_PRIORITY) +#error "STM32_IRQ_TIM2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM2_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM2 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim2_irq_init(void) { +#if defined(STM32_TIM2_IS_USED) + nvicEnableVector(STM32_TIM2_NUMBER, STM32_IRQ_TIM2_PRIORITY); +#endif +} + +static inline void tim2_irq_deinit(void) { +#if defined(STM32_TIM2_IS_USED) + nvicDisableVector(STM32_TIM2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM2_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM2 + gpt_lld_serve_interrupt(&GPTD2); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM2 + icu_lld_serve_interrupt(&ICUD2); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM2 + pwm_lld_serve_interrupt(&PWMD2); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM2 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc new file mode 100644 index 0000000..1b08998 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim20.inc @@ -0,0 +1,170 @@ +/* + 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 TIMv1/stm32_tim20.inc + * @brief Shared TIM20 handler. + * + * @addtogroup STM32_TIM20_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM20) +#error "STM32_HAS_TIM20 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM20) +#define STM32_GPT_USE_TIM20 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM20) +#define STM32_ICU_USE_TIM20 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM20) +#define STM32_PWM_USE_TIM20 FALSE +#endif +#if !defined(STM32_ST_USE_TIM20) +#define STM32_ST_USE_TIM20 FALSE +#endif + +#if STM32_HAS_TIM20 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM20_UP_PRIORITY) +#error "STM32_IRQ_TIM20_UP_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM20_CC_PRIORITY) +#error "STM32_IRQ_TIM20_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM20_UP_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM20_UP_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM20_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM20_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM20 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim20_irq_init(void) { +#if defined(STM32_TIM20_IS_USED) + nvicEnableVector(STM32_TIM20_UP_NUMBER, STM32_IRQ_TIM20_UP_PRIORITY); + nvicEnableVector(STM32_TIM20_CC_NUMBER, STM32_IRQ_TIM20_CC_PRIORITY); +#endif +} + +static inline void tim20_irq_deinit(void) { +#if defined(STM32_TIM20_IS_USED) + nvicDisableVector(STM32_TIM20_UP_NUMBER); + nvicDisableVector(STM32_TIM20_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM20_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM20-UP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM20_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM20 + pwm_lld_serve_interrupt(&GPTD20); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM20 + pwm_lld_serve_interrupt(&ICUD20); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM20 + pwm_lld_serve_interrupt(&PWMD20); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM20 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief TIM20-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM20_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if STM32_ICU_USE_TIM20 + pwm_lld_serve_interrupt(&ICUD20); +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM20 + pwm_lld_serve_interrupt(&PWMD20); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc new file mode 100644 index 0000000..4f98960 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim21.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim21.inc + * @brief Shared TIM21 handler. + * + * @addtogroup STM32_TIM21_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM21) +#error "STM32_HAS_TIM21 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM21) +#define STM32_GPT_USE_TIM21 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM21) +#define STM32_ICU_USE_TIM21 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM21) +#define STM32_PWM_USE_TIM21 FALSE +#endif +#if !defined(STM32_ST_USE_TIM21) +#define STM32_ST_USE_TIM21 FALSE +#endif + +#if STM32_HAS_TIM21 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM21_PRIORITY) +#error "STM32_IRQ_TIM21_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM21_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM21_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM21 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim21_irq_init(void) { +#if defined(STM32_TIM21_IS_USED) + nvicEnableVector(STM32_TIM21_NUMBER, STM32_IRQ_TIM21_PRIORITY); +#endif +} + +static inline void tim21_irq_deinit(void) { +#if defined(STM32_TIM21_IS_USED) + nvicDisableVector(STM32_TIM21_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM21_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM21 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM21_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM21 + gpt_lld_serve_interrupt(&GPTD21); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM21 + icu_lld_serve_interrupt(&ICUD21); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM21 + pwm_lld_serve_interrupt(&PWMD21); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM21 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc new file mode 100644 index 0000000..05ee7d3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim22.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim22.inc + * @brief Shared TIM22 handler. + * + * @addtogroup STM32_TIM22_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM22) +#error "STM32_HAS_TIM22 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM22) +#define STM32_GPT_USE_TIM22 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM22) +#define STM32_ICU_USE_TIM22 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM22) +#define STM32_PWM_USE_TIM22 FALSE +#endif +#if !defined(STM32_ST_USE_TIM22) +#define STM32_ST_USE_TIM22 FALSE +#endif + +#if STM32_HAS_TIM22 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM22_PRIORITY) +#error "STM32_IRQ_TIM22_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM22_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM22_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM22 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim22_irq_init(void) { +#if defined(STM32_TIM22_IS_USED) + nvicEnableVector(STM32_TIM22_NUMBER, STM32_IRQ_TIM22_PRIORITY); +#endif +} + +static inline void tim22_irq_deinit(void) { +#if defined(STM32_TIM22_IS_USED) + nvicDisableVector(STM32_TIM22_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM22_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM22 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM22_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM22 + gpt_lld_serve_interrupt(&GPTD22); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM22 + icu_lld_serve_interrupt(&ICUD22); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM22 + pwm_lld_serve_interrupt(&PWMD22); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM22 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc new file mode 100644 index 0000000..4521a92 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim3.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim3.inc + * @brief Shared TIM3 handler. + * + * @addtogroup STM32_TIM3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM3) +#error "STM32_HAS_TIM3 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM3) +#define STM32_GPT_USE_TIM3 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM3) +#define STM32_ICU_USE_TIM3 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM3) +#define STM32_PWM_USE_TIM3 FALSE +#endif +#if !defined(STM32_ST_USE_TIM3) +#define STM32_ST_USE_TIM3 FALSE +#endif + +#if STM32_HAS_TIM3 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM3_PRIORITY) +#error "STM32_IRQ_TIM3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM3_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM3 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim3_irq_init(void) { +#if defined(STM32_TIM3_IS_USED) + nvicEnableVector(STM32_TIM3_NUMBER, STM32_IRQ_TIM3_PRIORITY); +#endif +} + +static inline void tim3_irq_deinit(void) { +#if defined(STM32_TIM3_IS_USED) + nvicDisableVector(STM32_TIM3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM3_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM3 + gpt_lld_serve_interrupt(&GPTD3); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM3 + icu_lld_serve_interrupt(&ICUD3); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM3 + pwm_lld_serve_interrupt(&PWMD3); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM3 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc new file mode 100644 index 0000000..6df48dc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim4.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim4.inc + * @brief Shared TIM4 handler. + * + * @addtogroup STM32_TIM4_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM4) +#error "STM32_HAS_TIM4 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM4) +#define STM32_GPT_USE_TIM4 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM4) +#define STM32_ICU_USE_TIM4 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM4) +#define STM32_PWM_USE_TIM4 FALSE +#endif +#if !defined(STM32_ST_USE_TIM4) +#define STM32_ST_USE_TIM4 FALSE +#endif + +#if STM32_HAS_TIM4 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM4_PRIORITY) +#error "STM32_IRQ_TIM4_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM4_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM4_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM4 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim4_irq_init(void) { +#if defined(STM32_TIM4_IS_USED) + nvicEnableVector(STM32_TIM4_NUMBER, STM32_IRQ_TIM4_PRIORITY); +#endif +} + +static inline void tim4_irq_deinit(void) { +#if defined(STM32_TIM4_IS_USED) + nvicDisableVector(STM32_TIM4_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM4_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM4 + gpt_lld_serve_interrupt(&GPTD4); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM4 + icu_lld_serve_interrupt(&ICUD4); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM4 + pwm_lld_serve_interrupt(&PWMD4); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM4 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc new file mode 100644 index 0000000..35158b3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim5.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim5.inc + * @brief Shared TIM5 handler. + * + * @addtogroup STM32_TIM5_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM5) +#error "STM32_HAS_TIM5 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM5) +#define STM32_GPT_USE_TIM5 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM5) +#define STM32_ICU_USE_TIM5 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM5) +#define STM32_PWM_USE_TIM5 FALSE +#endif +#if !defined(STM32_ST_USE_TIM5) +#define STM32_ST_USE_TIM5 FALSE +#endif + +#if STM32_HAS_TIM5 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM5_PRIORITY) +#error "STM32_IRQ_TIM5_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM5_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM5_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM5 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim5_irq_init(void) { +#if defined(STM32_TIM5_IS_USED) + nvicEnableVector(STM32_TIM5_NUMBER, STM32_IRQ_TIM5_PRIORITY); +#endif +} + +static inline void tim5_irq_deinit(void) { +#if defined(STM32_TIM5_IS_USED) + nvicDisableVector(STM32_TIM5_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM5_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM5 + gpt_lld_serve_interrupt(&GPTD5); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM5 + icu_lld_serve_interrupt(&ICUD5); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM5 + pwm_lld_serve_interrupt(&PWMD5); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM5 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc new file mode 100644 index 0000000..200d103 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim6.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim6.inc + * @brief Shared TIM6 handler. + * + * @addtogroup STM32_TIM6_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM6) +#error "STM32_HAS_TIM6 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM6) +#define STM32_GPT_USE_TIM6 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM6) +#define STM32_ICU_USE_TIM6 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM6) +#define STM32_PWM_USE_TIM6 FALSE +#endif +#if !defined(STM32_ST_USE_TIM6) +#define STM32_ST_USE_TIM6 FALSE +#endif + +#if STM32_HAS_TIM6 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM6_PRIORITY) +#error "STM32_IRQ_TIM6_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM6_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM6_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM6 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim6_irq_init(void) { +#if defined(STM32_TIM6_IS_USED) + nvicEnableVector(STM32_TIM6_NUMBER, STM32_IRQ_TIM6_PRIORITY); +#endif +} + +static inline void tim6_irq_deinit(void) { +#if defined(STM32_TIM6_IS_USED) + nvicDisableVector(STM32_TIM6_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM6_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM6 + gpt_lld_serve_interrupt(&GPTD6); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM6 + icu_lld_serve_interrupt(&ICUD6); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM6 + pwm_lld_serve_interrupt(&PWMD6); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM6 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc new file mode 100644 index 0000000..8ea4e0f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim7.inc @@ -0,0 +1,133 @@ +/* + 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 TIMv1/stm32_tim7.inc + * @brief Shared TIM7 handler. + * + * @addtogroup STM32_TIM7_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM7) +#error "STM32_HAS_TIM7 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM7) +#define STM32_GPT_USE_TIM7 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM7) +#define STM32_ICU_USE_TIM7 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM7) +#define STM32_PWM_USE_TIM7 FALSE +#endif +#if !defined(STM32_ST_USE_TIM7) +#define STM32_ST_USE_TIM7 FALSE +#endif + +#if STM32_HAS_TIM7 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM7_PRIORITY) +#error "STM32_IRQ_TIM7_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM7_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM7_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM7 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim7_irq_init(void) { +#if defined(STM32_TIM7_IS_USED) + nvicEnableVector(STM32_TIM7_NUMBER, STM32_IRQ_TIM7_PRIORITY); +#endif +} + +static inline void tim7_irq_deinit(void) { +#if defined(STM32_TIM7_IS_USED) + nvicDisableVector(STM32_TIM7_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM7_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM7 + gpt_lld_serve_interrupt(&GPTD7); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM7 + icu_lld_serve_interrupt(&ICUD7); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM7 + pwm_lld_serve_interrupt(&PWMD7); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM7 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc new file mode 100644 index 0000000..db9219c --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8.inc @@ -0,0 +1,172 @@ +/* + 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 TIMv1/stm32_tim8.inc + * @brief Shared TIM8 handler. + * + * @addtogroup STM32_TIM8_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM8) +#error "STM32_HAS_TIM8 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM8) +#define STM32_GPT_USE_TIM8 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM8) +#define STM32_ICU_USE_TIM8 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM8) +#define STM32_PWM_USE_TIM8 FALSE +#endif +#if !defined(STM32_ST_USE_TIM8) +#define STM32_ST_USE_TIM8 FALSE +#endif + +#if STM32_HAS_TIM8 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM8_UP_PRIORITY) +#error "STM32_IRQ_TIM8_UP_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_CC_PRIORITY) +#error "STM32_IRQ_TIM8_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_UP_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_UP_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM8 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim8_irq_init(void) { +#if defined(STM32_TIM8_IS_USED) + nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_IRQ_TIM8_UP_PRIORITY); + nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_IRQ_TIM8_CC_PRIORITY); +#endif +} + +static inline void tim8_irq_deinit(void) { +#if defined(STM32_TIM8_IS_USED) + nvicDisableVector(STM32_TIM8_UP_NUMBER); + nvicDisableVector(STM32_TIM8_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM8_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM8-UP interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM8 + gpt_lld_serve_interrupt(&GPTD8); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM8 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief TIM8-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#endif +#if 1 + /* Not used by ST.*/ +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc new file mode 100644 index 0000000..fe23514 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/stm32_tim8_12_13_14.inc @@ -0,0 +1,343 @@ +/* + 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 TIMv1/stm32_tim8_12_13_14.inc + * @brief Shared TIM8, TIM12, TIM13, TIM14 handler. + * + * @addtogroup STM32_TIM8_TIM12_TIM13_TIM14_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_TIM8) +#error "STM32_HAS_TIM8 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM12) +#error "STM32_HAS_TIM12 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM13) +#error "STM32_HAS_TIM13 not defined in registry" +#endif + +#if !defined(STM32_HAS_TIM14) +#error "STM32_HAS_TIM14 not defined in registry" +#endif + +/* Driver checks for robustness, undefined USE macros are defaulted to + FALSE. This makes this module independent from drivers implementation.*/ +#if !defined(STM32_GPT_USE_TIM8) +#define STM32_GPT_USE_TIM8 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM8) +#define STM32_ICU_USE_TIM8 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM8) +#define STM32_PWM_USE_TIM8 FALSE +#endif +#if !defined(STM32_ST_USE_TIM8) +#define STM32_ST_USE_TIM8 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM12) +#define STM32_GPT_USE_TIM12 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM12) +#define STM32_ICU_USE_TIM12 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM12) +#define STM32_PWM_USE_TIM12 FALSE +#endif +#if !defined(STM32_ST_USE_TIM12) +#define STM32_ST_USE_TIM12 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM13) +#define STM32_GPT_USE_TIM13 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM13) +#define STM32_ICU_USE_TIM13 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM13) +#define STM32_PWM_USE_TIM13 FALSE +#endif +#if !defined(STM32_ST_USE_TIM13) +#define STM32_ST_USE_TIM13 FALSE +#endif + +#if !defined(STM32_GPT_USE_TIM14) +#define STM32_GPT_USE_TIM14 FALSE +#endif +#if !defined(STM32_ICU_USE_TIM14) +#define STM32_ICU_USE_TIM14 FALSE +#endif +#if !defined(STM32_PWM_USE_TIM14) +#define STM32_PWM_USE_TIM14 FALSE +#endif +#if !defined(STM32_ST_USE_TIM14) +#define STM32_ST_USE_TIM14 FALSE +#endif + +#if STM32_HAS_TIM8 || STM32_HAS_TIM12 || STM32_HAS_TIM13 || STM32_HAS_TIM14 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_TIM8_BRK_TIM12_PRIORITY) +#error "STM32_IRQ_TIM8_BRK_TIM12_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_UP_TIM13_PRIORITY) +#error "STM32_IRQ_TIM8_UP_TIM13_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY) +#error "STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY not defined in mcuconf.h" +#endif + +#if !defined(STM32_IRQ_TIM8_CC_PRIORITY) +#error "STM32_IRQ_TIM8_CC_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_BRK_TIM12_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_BRK_TIM12_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_UP_TIM13_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_UP_TIM13_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_TIM8_CC_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_TIM8_CC_PRIORITY" +#endif + +#endif /* STM32_HAS_TIM8 || STM32_HAS_TIM12 || STM32_HAS_TIM13 || STM32_HAS_TIM14 */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void tim8_tim12_tim13_tim14_irq_init(void) { +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM12_IS_USED) + nvicEnableVector(STM32_TIM8_BRK_TIM12_NUMBER, + STM32_IRQ_TIM8_BRK_TIM12_PRIORITY); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM13_IS_USED) + nvicEnableVector(STM32_TIM8_UP_TIM13_NUMBER, + STM32_IRQ_TIM8_UP_TIM13_PRIORITY); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM14_IS_USED) + nvicEnableVector(STM32_TIM8_TRGCO_TIM14_NUMBER, + STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY); +#endif +#if defined(STM32_TIM8_IS_USED) + nvicEnableVector(STM32_TIM8_CC_NUMBER, + STM32_IRQ_TIM8_CC_PRIORITY); +#endif +} + +static inline void tim8_tim12_tim13_tim14_irq_deinit(void) { +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM12_IS_USED) + nvicDisableVector(STM32_TIM8_BRK_TIM12_NUMBER); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM13_IS_USED) + nvicDisableVector(STM32_TIM8_UP_TIM13_NUMBER); +#endif +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM14_IS_USED) + nvicDisableVector(STM32_TIM8_TRGCO_TIM14_NUMBER); +#endif +#if defined(STM32_TIM8_IS_USED) + nvicDisableVector(STM32_TIM8_CC_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM12_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM8-BRK, TIM12 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_BRK_TIM12_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM12 + gpt_lld_serve_interrupt(&GPTD12); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM12 + icu_lld_serve_interrupt(&ICUD12); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM12 + pwm_lld_serve_interrupt(&PWMD12); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM12 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM13_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM8-UP, TIM13 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_UP_TIM13_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM8 + gpt_lld_serve_interrupt(&GPTD8); +#endif +#if STM32_GPT_USE_TIM13 + gpt_lld_serve_interrupt(&GPTD13); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#if STM32_ICU_USE_TIM13 + icu_lld_serve_interrupt(&ICUD13); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#if STM32_PWM_USE_TIM13 + pwm_lld_serve_interrupt(&PWMD13); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM8 + st_lld_serve_interrupt(); +#endif +#if STM32_ST_USE_TIM13 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM8_IS_USED) || defined(STM32_TIM14_IS_USED) || \ + defined(__DOXYGEN__) +/** + * @brief TIM8-TRG-COM, TIM14 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_TRGCO_TIM14_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT +#if STM32_GPT_USE_TIM14 + gpt_lld_serve_interrupt(&GPTD14); +#endif +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM14 + icu_lld_serve_interrupt(&ICUD14); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM14 + pwm_lld_serve_interrupt(&PWMD14); +#endif +#endif +#if 1 +#if STM32_ST_USE_TIM14 + st_lld_serve_interrupt(); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if defined(STM32_TIM8_IS_USED) || defined(__DOXYGEN__) +/** + * @brief TIM8-CC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_GPT + /* Not used by GPT.*/ +#endif +#if HAL_USE_ICU +#if STM32_ICU_USE_TIM8 + icu_lld_serve_interrupt(&ICUD8); +#endif +#endif +#if HAL_USE_PWM +#if STM32_PWM_USE_TIM8 + pwm_lld_serve_interrupt(&PWMD8); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt new file mode 100644 index 0000000..ed21572 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/TIMv1/tim_irq_mapping.txt @@ -0,0 +1,14 @@ +TIM units IRQ collisions mapping.
+
+ 1B 1UP 1TC 1CC 2 3 4 5 6 7 8B 8UP 8TC 8CC 9 10 11 12 13 14 15 16 17 18 19 20 21 22 LP1 LP2
+F0xx 1---1 2---2 * * * * * * * *
+F030 1---1 2---2 * * * * *
+F1xx 1 2 3 * * * * * * * 1 2 3
+F100 1 2 3 * * * * * * * 1 2 3
+F3xx 1 2 3 * * * * * * * * * * 1 2 3
+F37x * * * * * * * * * * * * * *
+F4xx 1 2 3 * * * * * * * 4 5 6 * 1 2 3 4 5 6
+F7xx 1 2 3 * * * * * * * 4 5 6 * 1 2 3 4 5 6 *
+L0xx * * * * * * *
+L1xx * * * * * * * * *
+L4xx 1 2 3 * * * * * * * * * * * 1 2 3 * *
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk new file mode 100644 index 0000000..2f65c1f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_SERIAL TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c
+endif
+ifneq ($(findstring HAL_USE_UART TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c new file mode 100644 index 0000000..188740e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c @@ -0,0 +1,650 @@ +/*
+ 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 USARTv1/hal_serial_lld.c
+ * @brief STM32 low level serial driver code.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief USART1 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+SerialDriver SD1;
+#endif
+
+/** @brief USART2 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+SerialDriver SD2;
+#endif
+
+/** @brief USART3 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+SerialDriver SD3;
+#endif
+
+/** @brief UART4 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+SerialDriver SD4;
+#endif
+
+/** @brief UART5 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+SerialDriver SD5;
+#endif
+
+/** @brief USART6 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+SerialDriver SD6;
+#endif
+
+/** @brief UART7 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+SerialDriver SD7;
+#endif
+
+/** @brief UART8 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+SerialDriver SD8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/** @brief Driver default configuration.*/
+static const SerialConfig default_config =
+{
+ SERIAL_DEFAULT_BITRATE,
+ 0,
+ USART_CR2_STOP1_BITS,
+ 0
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief USART initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration
+ */
+static void usart_init(SerialDriver *sdp, const SerialConfig *config) {
+ uint32_t fck;
+ USART_TypeDef *u = sdp->usart;
+
+ /* Baud rate setting.*/
+#if STM32_HAS_USART6
+ if ((sdp->usart == USART1) || (sdp->usart == USART6))
+#else
+ if (sdp->usart == USART1)
+#endif
+ fck = STM32_PCLK2 / config->speed;
+ else
+ fck = STM32_PCLK1 / config->speed;
+
+ /* Correcting USARTDIV when oversampling by 8 instead of 16.
+ Fraction is still 4 bits wide, but only lower 3 bits used.
+ Mantissa is doubled, but Fraction is left the same.*/
+#if defined(USART_CR1_OVER8)
+ if (config->cr1 & USART_CR1_OVER8)
+ fck = ((fck & ~7) * 2) | (fck & 7);
+#endif
+ u->BRR = fck;
+
+ /* Note that some bits are enforced.*/
+ u->CR2 = config->cr2 | USART_CR2_LBDIE;
+ u->CR3 = config->cr3 | USART_CR3_EIE;
+ u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE |
+ USART_CR1_RXNEIE | USART_CR1_TE |
+ USART_CR1_RE;
+ u->SR = 0;
+ (void)u->SR; /* SR reset step 1.*/
+ (void)u->DR; /* SR reset step 2.*/
+
+ /* Deciding mask to be applied on the data register on receive, this is
+ required in order to mask out the parity bit.*/
+ if ((config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_PCE) {
+ sdp->rxmask = 0x7F;
+ }
+ else {
+ sdp->rxmask = 0xFF;
+ }
+}
+
+/**
+ * @brief USART de-initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] u pointer to an USART I/O block
+ */
+static void usart_deinit(USART_TypeDef *u) {
+
+ u->CR1 = 0;
+ u->CR2 = 0;
+ u->CR3 = 0;
+}
+
+/**
+ * @brief Error handling routine.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] sr USART SR register value
+ */
+static void set_error(SerialDriver *sdp, uint16_t sr) {
+ eventflags_t sts = 0;
+
+ if (sr & USART_SR_ORE)
+ sts |= SD_OVERRUN_ERROR;
+ if (sr & USART_SR_PE)
+ sts |= SD_PARITY_ERROR;
+ if (sr & USART_SR_FE)
+ sts |= SD_FRAMING_ERROR;
+ if (sr & USART_SR_NE)
+ sts |= SD_NOISE_ERROR;
+ chnAddFlagsI(sdp, sts);
+}
+
+/**
+ * @brief Common IRQ handler.
+ *
+ * @param[in] sdp communication channel associated to the USART
+ */
+static void serve_interrupt(SerialDriver *sdp) {
+ USART_TypeDef *u = sdp->usart;
+ uint16_t cr1 = u->CR1;
+ uint16_t sr = u->SR;
+
+ /* Special case, LIN break detection.*/
+ if (sr & USART_SR_LBD) {
+ osalSysLockFromISR();
+ chnAddFlagsI(sdp, SD_BREAK_DETECTED);
+ u->SR = ~USART_SR_LBD;
+ osalSysUnlockFromISR();
+ }
+
+ /* Data available.*/
+ osalSysLockFromISR();
+ while (sr & (USART_SR_RXNE | USART_SR_ORE | USART_SR_NE | USART_SR_FE |
+ USART_SR_PE)) {
+ uint8_t b;
+
+ /* Error condition detection.*/
+ if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
+ set_error(sdp, sr);
+ b = (uint8_t)u->DR & sdp->rxmask;
+ if (sr & USART_SR_RXNE)
+ sdIncomingDataI(sdp, b);
+ sr = u->SR;
+ }
+ osalSysUnlockFromISR();
+
+ /* Transmission buffer empty.*/
+ if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) {
+ msg_t b;
+ osalSysLockFromISR();
+ b = oqGetI(&sdp->oqueue);
+ if (b < MSG_OK) {
+ chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
+ u->CR1 = cr1 & ~USART_CR1_TXEIE;
+ }
+ else
+ u->DR = b;
+ osalSysUnlockFromISR();
+ }
+
+ /* Physical transmission end.*/
+ if ((cr1 & USART_CR1_TCIE) && (sr & USART_SR_TC)) {
+ osalSysLockFromISR();
+ if (oqIsEmptyI(&sdp->oqueue)) {
+ chnAddFlagsI(sdp, CHN_TRANSMISSION_END);
+ u->CR1 = cr1 & ~USART_CR1_TCIE;
+ }
+ osalSysUnlockFromISR();
+ }
+}
+
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+static void notify1(io_queue_t *qp) {
+
+ (void)qp;
+ USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+static void notify2(io_queue_t *qp) {
+
+ (void)qp;
+ USART2->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+static void notify3(io_queue_t *qp) {
+
+ (void)qp;
+ USART3->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+static void notify4(io_queue_t *qp) {
+
+ (void)qp;
+ UART4->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+static void notify5(io_queue_t *qp) {
+
+ (void)qp;
+ UART5->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+static void notify6(io_queue_t *qp) {
+
+ (void)qp;
+ USART6->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+static void notify7(io_queue_t *qp) {
+
+ (void)qp;
+ UART7->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+static void notify8(io_queue_t *qp) {
+
+ (void)qp;
+ UART8->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+#if !defined(STM32_USART1_HANDLER)
+#error "STM32_USART1_HANDLER not defined"
+#endif
+/**
+ * @brief USART1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+#if !defined(STM32_USART2_HANDLER)
+#error "STM32_USART2_HANDLER not defined"
+#endif
+/**
+ * @brief USART2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+#if !defined(STM32_USART3_HANDLER)
+#error "STM32_USART3_HANDLER not defined"
+#endif
+/**
+ * @brief USART3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+#if !defined(STM32_UART4_HANDLER)
+#error "STM32_UART4_HANDLER not defined"
+#endif
+/**
+ * @brief UART4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+#if !defined(STM32_UART5_HANDLER)
+#error "STM32_UART5_HANDLER not defined"
+#endif
+/**
+ * @brief UART5 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+#if !defined(STM32_USART6_HANDLER)
+#error "STM32_USART6_HANDLER not defined"
+#endif
+/**
+ * @brief USART6 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+#if !defined(STM32_UART7_HANDLER)
+#error "STM32_UART7_HANDLER not defined"
+#endif
+/**
+ * @brief UART7 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+#if !defined(STM32_UART8_HANDLER)
+#error "STM32_UART8_HANDLER not defined"
+#endif
+/**
+ * @brief UART8 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level serial driver initialization.
+ *
+ * @notapi
+ */
+void sd_lld_init(void) {
+
+#if STM32_SERIAL_USE_USART1
+ sdObjectInit(&SD1, NULL, notify1);
+ SD1.usart = USART1;
+#endif
+
+#if STM32_SERIAL_USE_USART2
+ sdObjectInit(&SD2, NULL, notify2);
+ SD2.usart = USART2;
+#endif
+
+#if STM32_SERIAL_USE_USART3
+ sdObjectInit(&SD3, NULL, notify3);
+ SD3.usart = USART3;
+#endif
+
+#if STM32_SERIAL_USE_UART4
+ sdObjectInit(&SD4, NULL, notify4);
+ SD4.usart = UART4;
+#endif
+
+#if STM32_SERIAL_USE_UART5
+ sdObjectInit(&SD5, NULL, notify5);
+ SD5.usart = UART5;
+#endif
+
+#if STM32_SERIAL_USE_USART6
+ sdObjectInit(&SD6, NULL, notify6);
+ SD6.usart = USART6;
+#endif
+
+#if STM32_SERIAL_USE_UART7
+ sdObjectInit(&SD7, NULL, notify7);
+ SD7.usart = UART7;
+#endif
+
+#if STM32_SERIAL_USE_UART8
+ sdObjectInit(&SD8, NULL, notify8);
+ SD8.usart = UART8;
+#endif
+}
+
+/**
+ * @brief Low level serial driver configuration and (re)start.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration.
+ * If this parameter is set to @p NULL then a default
+ * configuration is used.
+ *
+ * @notapi
+ */
+void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
+
+ if (config == NULL)
+ config = &default_config;
+
+ if (sdp->state == SD_STOP) {
+#if STM32_SERIAL_USE_USART1
+ if (&SD1 == sdp) {
+ rccEnableUSART1(true);
+ nvicEnableVector(STM32_USART1_NUMBER, STM32_SERIAL_USART1_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_USART2
+ if (&SD2 == sdp) {
+ rccEnableUSART2(true);
+ nvicEnableVector(STM32_USART2_NUMBER, STM32_SERIAL_USART2_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_USART3
+ if (&SD3 == sdp) {
+ rccEnableUSART3(true);
+ nvicEnableVector(STM32_USART3_NUMBER, STM32_SERIAL_USART3_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_UART4
+ if (&SD4 == sdp) {
+ rccEnableUART4(true);
+ nvicEnableVector(STM32_UART4_NUMBER, STM32_SERIAL_UART4_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_UART5
+ if (&SD5 == sdp) {
+ rccEnableUART5(true);
+ nvicEnableVector(STM32_UART5_NUMBER, STM32_SERIAL_UART5_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_USART6
+ if (&SD6 == sdp) {
+ rccEnableUSART6(true);
+ nvicEnableVector(STM32_USART6_NUMBER, STM32_SERIAL_USART6_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_UART7
+ if (&SD7 == sdp) {
+ rccEnableUART7(true);
+ nvicEnableVector(STM32_UART7_NUMBER, STM32_SERIAL_UART7_PRIORITY);
+ }
+#endif
+#if STM32_SERIAL_USE_UART8
+ if (&SD8 == sdp) {
+ rccEnableUART8(true);
+ nvicEnableVector(STM32_UART8_NUMBER, STM32_SERIAL_UART8_PRIORITY);
+ }
+#endif
+ }
+ usart_init(sdp, config);
+}
+
+/**
+ * @brief Low level serial driver stop.
+ * @details De-initializes the USART, stops the associated clock, resets the
+ * interrupt vector.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ *
+ * @notapi
+ */
+void sd_lld_stop(SerialDriver *sdp) {
+
+ if (sdp->state == SD_READY) {
+ usart_deinit(sdp->usart);
+#if STM32_SERIAL_USE_USART1
+ if (&SD1 == sdp) {
+ rccDisableUSART1();
+ nvicDisableVector(STM32_USART1_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_USART2
+ if (&SD2 == sdp) {
+ rccDisableUSART2();
+ nvicDisableVector(STM32_USART2_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_USART3
+ if (&SD3 == sdp) {
+ rccDisableUSART3();
+ nvicDisableVector(STM32_USART3_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART4
+ if (&SD4 == sdp) {
+ rccDisableUART4();
+ nvicDisableVector(STM32_UART4_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART5
+ if (&SD5 == sdp) {
+ rccDisableUART5();
+ nvicDisableVector(STM32_UART5_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_USART6
+ if (&SD6 == sdp) {
+ rccDisableUSART6();
+ nvicDisableVector(STM32_USART6_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART7
+ if (&SD7 == sdp) {
+ rccDisableUART7();
+ nvicDisableVector(STM32_UART7_NUMBER);
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART8
+ if (&SD8 == sdp) {
+ rccDisableUART8();
+ nvicDisableVector(STM32_UART8_NUMBER);
+ return;
+ }
+#endif
+ }
+}
+
+#endif /* HAL_USE_SERIAL */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h new file mode 100644 index 0000000..de259a7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.h @@ -0,0 +1,362 @@ +/*
+ 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 USARTv1/hal_serial_lld.h
+ * @brief STM32 low level serial driver header.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#ifndef HAL_SERIAL_LLD_H
+#define HAL_SERIAL_LLD_H
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief USART1 driver enable switch.
+ * @details If set to @p TRUE the support for USART1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART1) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART1 FALSE
+#endif
+
+/**
+ * @brief USART2 driver enable switch.
+ * @details If set to @p TRUE the support for USART2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART2) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART2 FALSE
+#endif
+
+/**
+ * @brief USART3 driver enable switch.
+ * @details If set to @p TRUE the support for USART3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART3) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART3 FALSE
+#endif
+
+/**
+ * @brief UART4 driver enable switch.
+ * @details If set to @p TRUE the support for UART4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART4) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART4 FALSE
+#endif
+
+/**
+ * @brief UART5 driver enable switch.
+ * @details If set to @p TRUE the support for UART5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART5) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART5 FALSE
+#endif
+
+/**
+ * @brief USART6 driver enable switch.
+ * @details If set to @p TRUE the support for USART6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART6) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART6 FALSE
+#endif
+
+/**
+ * @brief UART7 driver enable switch.
+ * @details If set to @p TRUE the support for UART7 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART7) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART7 FALSE
+#endif
+
+/**
+ * @brief UART8 driver enable switch.
+ * @details If set to @p TRUE the support for UART8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART8) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART8 FALSE
+#endif
+
+/**
+ * @brief USART1 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART1_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART1_PRIORITY 12
+#endif
+
+/**
+ * @brief USART2 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART2_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART2_PRIORITY 12
+#endif
+
+/**
+ * @brief USART3 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART3_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART3_PRIORITY 12
+#endif
+
+/**
+ * @brief UART4 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART4_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART4_PRIORITY 12
+#endif
+
+/**
+ * @brief UART5 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART5_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART5_PRIORITY 12
+#endif
+
+/**
+ * @brief USART6 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART6_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART6_PRIORITY 12
+#endif
+
+/**
+ * @brief UART7 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART7_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART7_PRIORITY 12
+#endif
+
+/**
+ * @brief UART8 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART8_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART8_PRIORITY 12
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_SERIAL_USE_USART1 && !STM32_HAS_USART1
+#error "USART1 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_USART2 && !STM32_HAS_USART2
+#error "USART2 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_USART3 && !STM32_HAS_USART3
+#error "USART3 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART4 && !STM32_HAS_UART4
+#error "UART4 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART5 && !STM32_HAS_UART5
+#error "UART5 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_USART6 && !STM32_HAS_USART6
+#error "USART6 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART7 && !STM32_HAS_UART7
+#error "UART7 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART8 && !STM32_HAS_UART8
+#error "UART8 not present in the selected device"
+#endif
+
+#if !STM32_SERIAL_USE_USART1 && !STM32_SERIAL_USE_USART2 && \
+ !STM32_SERIAL_USE_USART3 && !STM32_SERIAL_USE_UART4 && \
+ !STM32_SERIAL_USE_UART5 && !STM32_SERIAL_USE_USART6 && \
+ !STM32_SERIAL_USE_UART7 && !STM32_SERIAL_USE_UART8
+#error "SERIAL driver activated but no USART/UART peripheral assigned"
+#endif
+
+#if STM32_SERIAL_USE_USART1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART1_PRIORITY)
+#error "Invalid IRQ priority assigned to USART1"
+#endif
+
+#if STM32_SERIAL_USE_USART2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART2_PRIORITY)
+#error "Invalid IRQ priority assigned to USART2"
+#endif
+
+#if STM32_SERIAL_USE_USART3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART3_PRIORITY)
+#error "Invalid IRQ priority assigned to USART3"
+#endif
+
+#if STM32_SERIAL_USE_UART4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART4_PRIORITY)
+#error "Invalid IRQ priority assigned to UART4"
+#endif
+
+#if STM32_SERIAL_USE_UART5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART5_PRIORITY)
+#error "Invalid IRQ priority assigned to UART5"
+#endif
+
+#if STM32_SERIAL_USE_USART6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART6_PRIORITY)
+#error "Invalid IRQ priority assigned to USART6"
+#endif
+
+#if STM32_SERIAL_USE_UART7 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART7_PRIORITY)
+#error "Invalid IRQ priority assigned to UART7"
+#endif
+
+#if STM32_SERIAL_USE_UART8 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART8_PRIORITY)
+#error "Invalid IRQ priority assigned to UART8"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 Serial Driver configuration structure.
+ * @details An instance of this structure must be passed to @p sdStart()
+ * in order to configure and start a serial driver operations.
+ * @note This structure content is architecture dependent, each driver
+ * implementation defines its own version and the custom static
+ * initializers.
+ */
+typedef struct {
+ /**
+ * @brief Bit rate.
+ */
+ uint32_t speed;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Initialization value for the CR1 register.
+ */
+ uint16_t cr1;
+ /**
+ * @brief Initialization value for the CR2 register.
+ */
+ uint16_t cr2;
+ /**
+ * @brief Initialization value for the CR3 register.
+ */
+ uint16_t cr3;
+} SerialConfig;
+
+/**
+ * @brief @p SerialDriver specific data.
+ */
+#define _serial_driver_data \
+ _base_asynchronous_channel_data \
+ /* Driver state.*/ \
+ sdstate_t state; \
+ /* Input queue.*/ \
+ input_queue_t iqueue; \
+ /* Output queue.*/ \
+ output_queue_t oqueue; \
+ /* Input circular buffer.*/ \
+ uint8_t ib[SERIAL_BUFFERS_SIZE]; \
+ /* Output circular buffer.*/ \
+ uint8_t ob[SERIAL_BUFFERS_SIZE]; \
+ /* End of the mandatory fields.*/ \
+ /* Pointer to the USART registers block.*/ \
+ USART_TypeDef *usart; \
+ /* Mask to be applied on received frames.*/ \
+ uint8_t rxmask;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*
+ * Extra USARTs definitions here (missing from the ST header file).
+ */
+#define USART_CR2_STOP1_BITS (0 << 12) /**< @brief CR2 1 stop bit value.*/
+#define USART_CR2_STOP0P5_BITS (1 << 12) /**< @brief CR2 0.5 stop bit value.*/
+#define USART_CR2_STOP2_BITS (2 << 12) /**< @brief CR2 2 stop bit value.*/
+#define USART_CR2_STOP1P5_BITS (3 << 12) /**< @brief CR2 1.5 stop bit value.*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SERIAL_USE_USART1 && !defined(__DOXYGEN__)
+extern SerialDriver SD1;
+#endif
+#if STM32_SERIAL_USE_USART2 && !defined(__DOXYGEN__)
+extern SerialDriver SD2;
+#endif
+#if STM32_SERIAL_USE_USART3 && !defined(__DOXYGEN__)
+extern SerialDriver SD3;
+#endif
+#if STM32_SERIAL_USE_UART4 && !defined(__DOXYGEN__)
+extern SerialDriver SD4;
+#endif
+#if STM32_SERIAL_USE_UART5 && !defined(__DOXYGEN__)
+extern SerialDriver SD5;
+#endif
+#if STM32_SERIAL_USE_USART6 && !defined(__DOXYGEN__)
+extern SerialDriver SD6;
+#endif
+#if STM32_SERIAL_USE_UART7 && !defined(__DOXYGEN__)
+extern SerialDriver SD7;
+#endif
+#if STM32_SERIAL_USE_UART8 && !defined(__DOXYGEN__)
+extern SerialDriver SD8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sd_lld_init(void);
+ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
+ void sd_lld_stop(SerialDriver *sdp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SERIAL */
+
+#endif /* HAL_SERIAL_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c new file mode 100644 index 0000000..d7da046 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.c @@ -0,0 +1,1008 @@ +/*
+ 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 USARTv1/hal_uart_lld.c
+ * @brief STM32 low level UART driver code.
+ *
+ * @addtogroup UART
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_UART || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define USART1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART1_RX_DMA_STREAM, \
+ STM32_USART1_RX_DMA_CHN)
+
+#define USART1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART1_TX_DMA_STREAM, \
+ STM32_USART1_TX_DMA_CHN)
+
+#define USART2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART2_RX_DMA_STREAM, \
+ STM32_USART2_RX_DMA_CHN)
+
+#define USART2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART2_TX_DMA_STREAM, \
+ STM32_USART2_TX_DMA_CHN)
+
+#define USART3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART3_RX_DMA_STREAM, \
+ STM32_USART3_RX_DMA_CHN)
+
+#define USART3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART3_TX_DMA_STREAM, \
+ STM32_USART3_TX_DMA_CHN)
+
+#define UART4_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART4_RX_DMA_STREAM, \
+ STM32_UART4_RX_DMA_CHN)
+
+#define UART4_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART4_TX_DMA_STREAM, \
+ STM32_UART4_TX_DMA_CHN)
+
+#define UART5_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART5_RX_DMA_STREAM, \
+ STM32_UART5_RX_DMA_CHN)
+
+#define UART5_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART5_TX_DMA_STREAM, \
+ STM32_UART5_TX_DMA_CHN)
+
+#define USART6_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART6_RX_DMA_STREAM, \
+ STM32_USART6_RX_DMA_CHN)
+
+#define USART6_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART6_TX_DMA_STREAM, \
+ STM32_USART6_TX_DMA_CHN)
+
+#define UART7_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART7_RX_DMA_STREAM, \
+ STM32_UART7_RX_DMA_CHN)
+
+#define UART7_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART7_TX_DMA_STREAM, \
+ STM32_UART7_TX_DMA_CHN)
+
+#define UART8_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART8_RX_DMA_STREAM, \
+ STM32_UART8_RX_DMA_CHN)
+
+#define UART8_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART8_TX_DMA_STREAM, \
+ STM32_UART8_TX_DMA_CHN)
+
+#define STM32_UART45_CR2_CHECK_MASK \
+ (USART_CR2_STOP_0 | USART_CR2_CLKEN | USART_CR2_CPOL | USART_CR2_CPHA | \
+ USART_CR2_LBCL)
+
+#define STM32_UART45_CR3_CHECK_MASK \
+ (USART_CR3_CTSIE | USART_CR3_CTSE | USART_CR3_RTSE | USART_CR3_SCEN | \
+ USART_CR3_NACK)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief USART1 UART driver identifier.*/
+#if STM32_UART_USE_USART1 || defined(__DOXYGEN__)
+UARTDriver UARTD1;
+#endif
+
+/** @brief USART2 UART driver identifier.*/
+#if STM32_UART_USE_USART2 || defined(__DOXYGEN__)
+UARTDriver UARTD2;
+#endif
+
+/** @brief USART3 UART driver identifier.*/
+#if STM32_UART_USE_USART3 || defined(__DOXYGEN__)
+UARTDriver UARTD3;
+#endif
+
+/** @brief UART4 UART driver identifier.*/
+#if STM32_UART_USE_UART4 || defined(__DOXYGEN__)
+UARTDriver UARTD4;
+#endif
+
+/** @brief UART5 UART driver identifier.*/
+#if STM32_UART_USE_UART5 || defined(__DOXYGEN__)
+UARTDriver UARTD5;
+#endif
+
+/** @brief USART6 UART driver identifier.*/
+#if STM32_UART_USE_USART6 || defined(__DOXYGEN__)
+UARTDriver UARTD6;
+#endif
+
+/** @brief UART7 UART driver identifier.*/
+#if STM32_UART_USE_UART7 || defined(__DOXYGEN__)
+UARTDriver UARTD7;
+#endif
+
+/** @brief UART8 UART driver identifier.*/
+#if STM32_UART_USE_UART8 || defined(__DOXYGEN__)
+UARTDriver UARTD8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Status bits translation.
+ *
+ * @param[in] sr USART SR register value
+ *
+ * @return The error flags.
+ */
+static uartflags_t translate_errors(uint16_t sr) {
+ uartflags_t sts = 0;
+
+ if (sr & USART_SR_ORE)
+ sts |= UART_OVERRUN_ERROR;
+ if (sr & USART_SR_PE)
+ sts |= UART_PARITY_ERROR;
+ if (sr & USART_SR_FE)
+ sts |= UART_FRAMING_ERROR;
+ if (sr & USART_SR_NE)
+ sts |= UART_NOISE_ERROR;
+ if (sr & USART_SR_LBD)
+ sts |= UART_BREAK_DETECTED;
+ return sts;
+}
+
+/**
+ * @brief Puts the receiver in the UART_RX_IDLE state.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
+ uint32_t mode;
+
+ /* RX DMA channel preparation, if the char callback is defined then the
+ TCIE interrupt is enabled too.*/
+ if (uartp->config->rxchar_cb == NULL)
+ mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC;
+ else
+ mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE;
+ dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf);
+ dmaStreamSetTransactionSize(uartp->dmarx, 1);
+ dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | mode);
+ dmaStreamEnable(uartp->dmarx);
+}
+
+/**
+ * @brief USART de-initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void usart_stop(UARTDriver *uartp) {
+
+ /* Stops RX and TX DMA channels.*/
+ dmaStreamDisable(uartp->dmarx);
+ dmaStreamDisable(uartp->dmatx);
+
+ /* Stops USART operations.*/
+ uartp->usart->CR1 = 0;
+ uartp->usart->CR2 = 0;
+ uartp->usart->CR3 = 0;
+}
+
+/**
+ * @brief USART initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void usart_start(UARTDriver *uartp) {
+ uint32_t fck;
+ uint16_t cr1;
+ USART_TypeDef *u = uartp->usart;
+
+ /* Defensive programming, starting from a clean state.*/
+ usart_stop(uartp);
+
+ /* Baud rate setting.*/
+#if STM32_HAS_USART6
+ if ((uartp->usart == USART1) || (uartp->usart == USART6))
+#else
+ if (uartp->usart == USART1)
+#endif
+ fck = STM32_PCLK2 / uartp->config->speed;
+ else
+ fck = STM32_PCLK1 / uartp->config->speed;
+
+ /* Correcting USARTDIV when oversampling by 8 instead of 16.
+ Fraction is still 4 bits wide, but only lower 3 bits used.
+ Mantissa is doubled, but Fraction is left the same.*/
+#if defined(USART_CR1_OVER8)
+ if (uartp->config->cr1 & USART_CR1_OVER8)
+ fck = ((fck & ~7) * 2) | (fck & 7);
+#endif
+ u->BRR = fck;
+
+ /* Resetting eventual pending status flags.*/
+ (void)u->SR; /* SR reset step 1.*/
+ (void)u->DR; /* SR reset step 2.*/
+ u->SR = 0;
+
+ /* Note that some bits are enforced because required for correct driver
+ operations.*/
+ u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE;
+ u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR |
+ USART_CR3_EIE;
+
+ /* Mustn't ever set TCIE here - if done, it causes an immediate
+ interrupt.*/
+ cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
+ u->CR1 = uartp->config->cr1 | cr1;
+
+ /* Starting the receiver idle loop.*/
+ uart_enter_rx_idle_loop(uartp);
+}
+
+/**
+ * @brief RX DMA common service routine.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_UART_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_UART_DMA_ERROR_HOOK(uartp);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (uartp->rxstate == UART_RX_IDLE) {
+ /* Receiver in idle state, a callback is generated, if enabled, for each
+ received character and then the driver stays in the same state.*/
+ _uart_rx_idle_code(uartp);
+ }
+ else {
+ /* Receiver in active state, a callback is generated, if enabled, after
+ a completed transfer.*/
+ dmaStreamDisable(uartp->dmarx);
+ _uart_rx_complete_isr_code(uartp);
+ }
+}
+
+/**
+ * @brief TX DMA common service routine.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_UART_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_UART_DMA_ERROR_HOOK(uartp);
+ }
+#else
+ (void)flags;
+#endif
+
+ dmaStreamDisable(uartp->dmatx);
+
+ /* A callback is generated, if enabled, after a completed transfer.*/
+ _uart_tx1_isr_code(uartp);
+}
+
+/**
+ * @brief USART common service routine.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void serve_usart_irq(UARTDriver *uartp) {
+ uint16_t sr;
+ USART_TypeDef *u = uartp->usart;
+ uint32_t cr1 = u->CR1;
+
+ sr = u->SR; /* SR reset step 1.*/
+ (void)u->DR; /* SR reset step 2.*/
+
+ if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE |
+ USART_SR_FE | USART_SR_PE)) {
+ u->SR = ~USART_SR_LBD;
+ _uart_rx_error_isr_code(uartp, translate_errors(sr));
+ }
+
+ if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) {
+ /* TC interrupt cleared and disabled.*/
+ u->SR = ~USART_SR_TC;
+ u->CR1 = cr1 & ~USART_CR1_TCIE;
+
+ /* End of transmission, a callback is generated.*/
+ _uart_tx2_isr_code(uartp);
+ }
+
+ /* Timeout interrupt sources are only checked if enabled in CR1.*/
+ if ((cr1 & USART_CR1_IDLEIE) && (sr & USART_SR_IDLE)) {
+ _uart_timeout_isr_code(uartp);
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_UART_USE_USART1 || defined(__DOXYGEN__)
+#if !defined(STM32_USART1_HANDLER)
+#error "STM32_USART1_HANDLER not defined"
+#endif
+/**
+ * @brief USART1 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_USART1 */
+
+#if STM32_UART_USE_USART2 || defined(__DOXYGEN__)
+#if !defined(STM32_USART2_HANDLER)
+#error "STM32_USART2_HANDLER not defined"
+#endif
+/**
+ * @brief USART2 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_USART2 */
+
+#if STM32_UART_USE_USART3 || defined(__DOXYGEN__)
+#if !defined(STM32_USART3_HANDLER)
+#error "STM32_USART3_HANDLER not defined"
+#endif
+/**
+ * @brief USART3 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_USART3 */
+
+#if STM32_UART_USE_UART4 || defined(__DOXYGEN__)
+#if !defined(STM32_UART4_HANDLER)
+#error "STM32_UART4_HANDLER not defined"
+#endif
+/**
+ * @brief UART4 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_UART4 */
+
+#if STM32_UART_USE_UART5 || defined(__DOXYGEN__)
+#if !defined(STM32_UART5_HANDLER)
+#error "STM32_UART5_HANDLER not defined"
+#endif
+/**
+ * @brief UART5 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_UART5 */
+
+#if STM32_UART_USE_USART6 || defined(__DOXYGEN__)
+#if !defined(STM32_USART6_HANDLER)
+#error "STM32_USART6_HANDLER not defined"
+#endif
+/**
+ * @brief USART6 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_USART6 */
+
+#if STM32_UART_USE_UART7 || defined(__DOXYGEN__)
+#if !defined(STM32_UART7_HANDLER)
+#error "STM32_UART7_HANDLER not defined"
+#endif
+/**
+ * @brief UART7 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_UART7 */
+
+#if STM32_UART_USE_UART8 || defined(__DOXYGEN__)
+#if !defined(STM32_UART8_HANDLER)
+#error "STM32_UART8_HANDLER not defined"
+#endif
+/**
+ * @brief UART8 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_usart_irq(&UARTD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_UART_USE_UART8 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level UART driver initialization.
+ *
+ * @notapi
+ */
+void uart_lld_init(void) {
+
+#if STM32_UART_USE_USART1
+ uartObjectInit(&UARTD1);
+ UARTD1.usart = USART1;
+ UARTD1.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD1.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD1.dmarx = NULL;
+ UARTD1.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_USART2
+ uartObjectInit(&UARTD2);
+ UARTD2.usart = USART2;
+ UARTD2.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD2.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD2.dmarx = NULL;
+ UARTD2.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_USART3
+ uartObjectInit(&UARTD3);
+ UARTD3.usart = USART3;
+ UARTD3.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD3.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD3.dmarx = NULL;
+ UARTD3.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_UART4
+ uartObjectInit(&UARTD4);
+ UARTD4.usart = UART4;
+ UARTD4.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD4.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD4.dmarx = NULL;
+ UARTD4.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_UART5
+ uartObjectInit(&UARTD5);
+ UARTD5.usart = UART5;
+ UARTD5.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD5.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD5.dmarx = NULL;
+ UARTD5.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_USART6
+ uartObjectInit(&UARTD6);
+ UARTD6.usart = USART6;
+ UARTD6.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD6.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD6.dmarx = NULL;
+ UARTD6.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_UART7
+ uartObjectInit(&UARTD7);
+ UARTD7.usart = UART7;
+ UARTD7.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD7.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD7.dmarx = NULL;
+ UARTD7.dmatx = NULL;
+#endif
+
+#if STM32_UART_USE_UART8
+ uartObjectInit(&UARTD8);
+ UARTD8.usart = UART8;
+ UARTD8.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD8.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD8.dmarx = NULL;
+ UARTD8.dmatx = NULL;
+#endif
+}
+
+/**
+ * @brief Configures and activates the UART peripheral.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+void uart_lld_start(UARTDriver *uartp) {
+
+ if (uartp->state == UART_STOP) {
+#if STM32_UART_USE_USART1
+ if (&UARTD1 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART1_RX_DMA_STREAM,
+ STM32_UART_USART1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART1_TX_DMA_STREAM,
+ STM32_UART_USART1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART1(true);
+ nvicEnableVector(STM32_USART1_NUMBER, STM32_UART_USART1_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_USART2
+ if (&UARTD2 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART2_RX_DMA_STREAM,
+ STM32_UART_USART2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART2_TX_DMA_STREAM,
+ STM32_UART_USART2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART2(true);
+ nvicEnableVector(STM32_USART2_NUMBER, STM32_UART_USART2_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_USART3
+ if (&UARTD3 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART3_RX_DMA_STREAM,
+ STM32_UART_USART3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART3_TX_DMA_STREAM,
+ STM32_UART_USART3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART3(true);
+ nvicEnableVector(STM32_USART3_NUMBER, STM32_UART_USART3_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_UART4
+ if (&UARTD4 == uartp) {
+
+ osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0,
+ "specified invalid bits in UART4 CR2 register settings");
+ osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0,
+ "specified invalid bits in UART4 CR3 register settings");
+
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART4_RX_DMA_STREAM,
+ STM32_UART_UART4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART4_TX_DMA_STREAM,
+ STM32_UART_UART4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART4(true);
+ nvicEnableVector(STM32_UART4_NUMBER, STM32_UART_UART4_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART4_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART4_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_UART5
+ if (&UARTD5 == uartp) {
+
+ osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0,
+ "specified invalid bits in UART5 CR2 register settings");
+ osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0,
+ "specified invalid bits in UART5 CR3 register settings");
+
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART5_RX_DMA_STREAM,
+ STM32_UART_UART5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART5_TX_DMA_STREAM,
+ STM32_UART_UART5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART5(true);
+ nvicEnableVector(STM32_UART5_NUMBER, STM32_UART_UART5_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART5_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART5_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_USART6
+ if (&UARTD6 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART6_RX_DMA_STREAM,
+ STM32_UART_USART6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART6_TX_DMA_STREAM,
+ STM32_UART_USART6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART6(true);
+ nvicEnableVector(STM32_USART6_NUMBER, STM32_UART_USART6_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART6_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART6_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_UART7
+ if (&UARTD7 == uartp) {
+
+ osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0,
+ "specified invalid bits in UART7 CR2 register settings");
+ osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0,
+ "specified invalid bits in UART7 CR3 register settings");
+
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART7_RX_DMA_STREAM,
+ STM32_UART_UART7_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART7_TX_DMA_STREAM,
+ STM32_UART_UART7_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART7(true);
+ nvicEnableVector(STM32_UART7_NUMBER, STM32_UART_UART7_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART7_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART7_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY);
+ }
+#endif
+
+#if STM32_UART_USE_UART8
+ if (&UARTD8 == uartp) {
+
+ osalDbgAssert((uartp->config->cr2 & STM32_UART45_CR2_CHECK_MASK) == 0,
+ "specified invalid bits in UART8 CR2 register settings");
+ osalDbgAssert((uartp->config->cr3 & STM32_UART45_CR3_CHECK_MASK) == 0,
+ "specified invalid bits in UART8 CR3 register settings");
+
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART8_RX_DMA_STREAM,
+ STM32_UART_UART8_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART8_TX_DMA_STREAM,
+ STM32_UART_UART8_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART8(true);
+ nvicEnableVector(STM32_UART8_NUMBER, STM32_UART_UART8_IRQ_PRIORITY);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART8_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART8_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY);
+ }
+#endif
+
+ /* Static DMA setup, the transfer size depends on the USART settings,
+ it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/
+ if ((uartp->config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M) {
+ uartp->dmarxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ uartp->dmatxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ }
+ dmaStreamSetPeripheral(uartp->dmarx, &uartp->usart->DR);
+ dmaStreamSetPeripheral(uartp->dmatx, &uartp->usart->DR);
+ uartp->rxbuf = 0;
+ }
+
+ uartp->rxstate = UART_RX_IDLE;
+ uartp->txstate = UART_TX_IDLE;
+ usart_start(uartp);
+}
+
+/**
+ * @brief Deactivates the UART peripheral.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+void uart_lld_stop(UARTDriver *uartp) {
+
+ if (uartp->state == UART_READY) {
+ usart_stop(uartp);
+ dmaStreamFreeI(uartp->dmarx);
+ dmaStreamFreeI(uartp->dmatx);
+ uartp->dmarx = NULL;
+ uartp->dmatx = NULL;
+
+#if STM32_UART_USE_USART1
+ if (&UARTD1 == uartp) {
+ nvicDisableVector(STM32_USART1_NUMBER);
+ rccDisableUSART1();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_USART2
+ if (&UARTD2 == uartp) {
+ nvicDisableVector(STM32_USART2_NUMBER);
+ rccDisableUSART2();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_USART3
+ if (&UARTD3 == uartp) {
+ nvicDisableVector(STM32_USART3_NUMBER);
+ rccDisableUSART3();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART4
+ if (&UARTD4 == uartp) {
+ nvicDisableVector(STM32_UART4_NUMBER);
+ rccDisableUART4();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART5
+ if (&UARTD5 == uartp) {
+ nvicDisableVector(STM32_UART5_NUMBER);
+ rccDisableUART5();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_USART6
+ if (&UARTD6 == uartp) {
+ nvicDisableVector(STM32_USART6_NUMBER);
+ rccDisableUSART6();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART7
+ if (&UARTD7 == uartp) {
+ nvicDisableVector(STM32_UART7_NUMBER);
+ rccDisableUART7();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART8
+ if (&UARTD8 == uartp) {
+ nvicDisableVector(STM32_UART8_NUMBER);
+ rccDisableUART8();
+ return;
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts a transmission on the UART peripheral.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] n number of data frames to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
+
+ /* TX DMA channel preparation.*/
+ dmaStreamSetMemory0(uartp->dmatx, txbuf);
+ dmaStreamSetTransactionSize(uartp->dmatx, n);
+ dmaStreamSetMode(uartp->dmatx, uartp->dmatxmode | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);
+
+ /* Only enable TC interrupt if there's a callback attached to it or
+ if called from uartSendFullTimeout(). Also we need to clear TC flag
+ which could be set before.*/
+#if UART_USE_WAIT == TRUE
+ if ((uartp->config->txend2_cb != NULL) || (uartp->early == false)) {
+#else
+ if (uartp->config->txend2_cb != NULL) {
+#endif
+ uartp->usart->SR = ~USART_SR_TC;
+ uartp->usart->CR1 |= USART_CR1_TCIE;
+ }
+
+ /* Starting transfer.*/
+ dmaStreamEnable(uartp->dmatx);
+}
+
+/**
+ * @brief Stops any ongoing transmission.
+ * @note Stopping a transmission also suppresses the transmission callbacks.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @return The number of data frames not transmitted by the
+ * stopped transmit operation.
+ *
+ * @notapi
+ */
+size_t uart_lld_stop_send(UARTDriver *uartp) {
+
+ dmaStreamDisable(uartp->dmatx);
+
+ return dmaStreamGetTransactionSize(uartp->dmatx);
+}
+
+/**
+ * @brief Starts a receive operation on the UART peripheral.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] n number of data frames to send
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
+
+ /* Stopping previous activity (idle state).*/
+ dmaStreamDisable(uartp->dmarx);
+
+ /* RX DMA channel preparation.*/
+ dmaStreamSetMemory0(uartp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(uartp->dmarx, n);
+ dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);
+
+ /* Starting transfer.*/
+ dmaStreamEnable(uartp->dmarx);
+}
+
+/**
+ * @brief Stops any ongoing receive operation.
+ * @note Stopping a receive operation also suppresses the receive callbacks.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @return The number of data frames not received by the
+ * stopped receive operation.
+ *
+ * @notapi
+ */
+size_t uart_lld_stop_receive(UARTDriver *uartp) {
+ size_t n;
+
+ dmaStreamDisable(uartp->dmarx);
+ n = dmaStreamGetTransactionSize(uartp->dmarx);
+ uart_enter_rx_idle_loop(uartp);
+
+ return n;
+}
+
+#endif /* HAL_USE_UART */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h new file mode 100644 index 0000000..ae0f4d3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv1/hal_uart_lld.h @@ -0,0 +1,758 @@ +/*
+ 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 USARTv1/hal_uart_lld.h
+ * @brief STM32 low level UART driver header.
+ *
+ * @addtogroup UART
+ * @{
+ */
+
+#ifndef HAL_UART_LLD_H
+#define HAL_UART_LLD_H
+
+#if HAL_USE_UART || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief UART driver on USART1 enable switch.
+ * @details If set to @p TRUE the support for USART1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART1) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART1 FALSE
+#endif
+
+/**
+ * @brief UART driver on USART2 enable switch.
+ * @details If set to @p TRUE the support for USART2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART2) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART2 FALSE
+#endif
+
+/**
+ * @brief UART driver on USART3 enable switch.
+ * @details If set to @p TRUE the support for USART3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART3) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART3 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART4 enable switch.
+ * @details If set to @p TRUE the support for UART4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART4) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART4 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART5 enable switch.
+ * @details If set to @p TRUE the support for UART5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART5) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART5 FALSE
+#endif
+
+/**
+ * @brief UART driver on USART6 enable switch.
+ * @details If set to @p TRUE the support for USART6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART6) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART6 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART7 enable switch.
+ * @details If set to @p TRUE the support for UART7 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART7) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART7 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART8 enable switch.
+ * @details If set to @p TRUE the support for UART8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART8) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART8 FALSE
+#endif
+
+/**
+ * @brief USART1 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART1_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART2 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART2_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART3 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART3_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART4 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART4_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART5 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART5_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART6 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART6_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART6_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART7 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART7_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART7_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART8 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART8_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART8_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART1_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART2_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART3_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART4_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART5 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART5_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART5_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART6 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART6_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART6_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART7 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART7_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART7_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART8 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART8_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART8_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART 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_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_UART_USE_USART1 && !STM32_HAS_USART1
+#error "USART1 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_USART2 && !STM32_HAS_USART2
+#error "USART2 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_USART3 && !STM32_HAS_USART3
+#error "USART3 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART4
+#if !STM32_HAS_UART4
+#error "UART4 not present in the selected device"
+#endif
+
+#if !defined(STM32F2XX) && !defined(STM32F4XX) && !defined(STM32L151xE) && \
+ !defined(STM32L152xE) && !defined(STM32L162xE)
+#error "UART4 DMA access not supported in this platform"
+#endif
+#endif /* STM32_UART_USE_UART4 */
+
+#if STM32_UART_USE_UART5
+#if !STM32_HAS_UART5
+#error "UART5 not present in the selected device"
+#endif
+
+#if !defined(STM32F2XX) && !defined(STM32F4XX) && !defined(STM32L151xE) && \
+ !defined(STM32L152xE) && !defined(STM32L162xE)
+#error "UART5 DMA access not supported in this platform"
+#endif
+#endif /* STM32_UART_USE_UART5 */
+
+#if STM32_UART_USE_USART6 && !STM32_HAS_USART6
+#error "USART6 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART7 && !STM32_HAS_UART7
+#error "UART7 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART8 && !STM32_HAS_UART8
+#error "UART8 not present in the selected device"
+#endif
+
+#if !STM32_UART_USE_USART1 && !STM32_UART_USE_USART2 && \
+ !STM32_UART_USE_USART3 && !STM32_UART_USE_UART4 && \
+ !STM32_UART_USE_UART5 && !STM32_UART_USE_USART6 && \
+ !STM32_UART_USE_UART7 && !STM32_UART_USE_UART8
+#error "UART driver activated but no USART/UART peripheral assigned"
+#endif
+
+#if STM32_UART_USE_USART1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART1"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART2"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART3"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART4"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART5"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART6_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART6"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART7_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART7"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART8_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART8"
+#endif
+
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART1"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART2"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART3"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART4"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART5_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART5"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART6_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART6"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART7_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART7"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART8_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART8"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+ reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_UART_USE_USART1 && (!defined(STM32_UART_USART1_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART1_TX_DMA_STREAM))
+#error "USART1 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_USART2 && (!defined(STM32_UART_USART2_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART2_TX_DMA_STREAM))
+#error "USART2 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_USART3 && (!defined(STM32_UART_USART3_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART3_TX_DMA_STREAM))
+#error "USART3 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART4 && (!defined(STM32_UART_UART4_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART4_TX_DMA_STREAM))
+#error "UART4 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART5 && (!defined(STM32_UART_UART5_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART5_TX_DMA_STREAM))
+#error "UART5 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_USART6 && (!defined(STM32_UART_USART6_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART6_TX_DMA_STREAM))
+#error "USART6 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART7 && (!defined(STM32_UART_UART7_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART7_TX_DMA_STREAM))
+#error "UART7 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART8 && (!defined(STM32_UART_UART8_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART8_TX_DMA_STREAM))
+#error "UART8 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_RX_DMA_STREAM, \
+ STM32_USART1_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART1 RX"
+#endif
+
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_TX_DMA_STREAM, \
+ STM32_USART1_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART1 TX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_RX_DMA_STREAM, \
+ STM32_USART2_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART2 RX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_TX_DMA_STREAM, \
+ STM32_USART2_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART2 TX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_RX_DMA_STREAM, \
+ STM32_USART3_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART3 RX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_TX_DMA_STREAM, \
+ STM32_USART3_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART3 TX"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_RX_DMA_STREAM, \
+ STM32_UART4_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART4 RX"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_TX_DMA_STREAM, \
+ STM32_UART4_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART4 TX"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_RX_DMA_STREAM, \
+ STM32_UART5_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART5 RX"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_TX_DMA_STREAM, \
+ STM32_UART5_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART5 TX"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_RX_DMA_STREAM, \
+ STM32_USART6_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART6 RX"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_TX_DMA_STREAM, \
+ STM32_USART6_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART6 TX"
+#endif
+#endif /* STM32_ADVANCED_DMA */
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_RX_DMA_STREAM, \
+ STM32_UART7_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART7 RX"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_TX_DMA_STREAM, \
+ STM32_UART7_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART7 TX"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_RX_DMA_STREAM, \
+ STM32_UART8_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART8 RX"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_TX_DMA_STREAM, \
+ STM32_UART8_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART8 TX"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief UART driver condition flags type.
+ */
+typedef uint32_t uartflags_t;
+
+/**
+ * @brief Structure representing an UART driver.
+ */
+typedef struct UARTDriver UARTDriver;
+
+/**
+ * @brief Generic UART notification callback type.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+typedef void (*uartcb_t)(UARTDriver *uartp);
+
+/**
+ * @brief Character received UART notification callback type.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] c received character
+ */
+typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c);
+
+/**
+ * @brief Receive error UART notification callback type.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] e receive error mask
+ */
+typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e);
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief End of transmission buffer callback.
+ */
+ uartcb_t txend1_cb;
+ /**
+ * @brief Physical end of transmission callback.
+ */
+ uartcb_t txend2_cb;
+ /**
+ * @brief Receive buffer filled callback.
+ */
+ uartcb_t rxend_cb;
+ /**
+ * @brief Character received while out if the @p UART_RECEIVE state.
+ */
+ uartccb_t rxchar_cb;
+ /**
+ * @brief Receive error callback.
+ */
+ uartecb_t rxerr_cb;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Receiver timeout callback.
+ * @details Handles idle interrupts depending on configured
+ * flags in CR registers and supported hardware features.
+ */
+ uartcb_t timeout_cb;
+ /**
+ * @brief Bit rate.
+ */
+ uint32_t speed;
+ /**
+ * @brief Initialization value for the CR1 register.
+ */
+ uint16_t cr1;
+ /**
+ * @brief Initialization value for the CR2 register.
+ */
+ uint16_t cr2;
+ /**
+ * @brief Initialization value for the CR3 register.
+ */
+ uint16_t cr3;
+} UARTConfig;
+
+/**
+ * @brief Structure representing an UART driver.
+ */
+struct UARTDriver {
+ /**
+ * @brief Driver state.
+ */
+ uartstate_t state;
+ /**
+ * @brief Transmitter state.
+ */
+ uarttxstate_t txstate;
+ /**
+ * @brief Receiver state.
+ */
+ uartrxstate_t rxstate;
+ /**
+ * @brief Current configuration data.
+ */
+ const UARTConfig *config;
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
+#if defined(UART_DRIVER_EXT_FIELDS)
+ UART_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the USART registers block.
+ */
+ USART_TypeDef *usart;
+ /**
+ * @brief Receive DMA mode bit mask.
+ */
+ uint32_t dmarxmode;
+ /**
+ * @brief Send DMA mode bit mask.
+ */
+ uint32_t dmatxmode;
+ /**
+ * @brief Receive DMA channel.
+ */
+ const stm32_dma_stream_t *dmarx;
+ /**
+ * @brief Transmit DMA channel.
+ */
+ const stm32_dma_stream_t *dmatx;
+ /**
+ * @brief Default receive buffer while into @p UART_RX_IDLE state.
+ */
+ volatile uint16_t rxbuf;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_UART_USE_USART1 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD1;
+#endif
+
+#if STM32_UART_USE_USART2 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD2;
+#endif
+
+#if STM32_UART_USE_USART3 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD3;
+#endif
+
+#if STM32_UART_USE_UART4 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD4;
+#endif
+
+#if STM32_UART_USE_UART5 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD5;
+#endif
+
+#if STM32_UART_USE_USART6 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD6;
+#endif
+
+#if STM32_UART_USE_UART7 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD7;
+#endif
+
+#if STM32_UART_USE_UART8 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void uart_lld_init(void);
+ void uart_lld_start(UARTDriver *uartp);
+ void uart_lld_stop(UARTDriver *uartp);
+ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf);
+ size_t uart_lld_stop_send(UARTDriver *uartp);
+ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf);
+ size_t uart_lld_stop_receive(UARTDriver *uartp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_UART */
+
+#endif /* HAL_UART_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk new file mode 100644 index 0000000..2de63f8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/driver.mk @@ -0,0 +1,13 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_SERIAL TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c
+endif
+ifneq ($(findstring HAL_USE_UART TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c new file mode 100644 index 0000000..7c89ecf --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c @@ -0,0 +1,913 @@ +/*
+ 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 USARTv2/hal_serial_lld.c
+ * @brief STM32 low level serial driver code.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* For compatibility for those devices without LIN support in the USARTs.*/
+#if !defined(USART_ISR_LBDF)
+#define USART_ISR_LBDF 0
+#endif
+
+#if !defined(USART_CR2_LBDIE)
+#define USART_CR2_LBDIE 0
+#endif
+
+/* Differences in L4+ headers.*/
+#if !defined(USART_CR1_TXEIE)
+#define USART_CR1_TXEIE USART_CR1_TXEIE_TXFNFIE
+#endif
+
+#if !defined(USART_CR1_RXNEIE)
+#define USART_CR1_RXNEIE USART_CR1_RXNEIE_RXFNEIE
+#endif
+
+#if !defined(USART_ISR_TXE)
+#define USART_ISR_TXE USART_ISR_TXE_TXFNF
+#endif
+
+#if !defined(USART_ISR_RXNE)
+#define USART_ISR_RXNE USART_ISR_RXNE_RXFNE
+#endif
+
+/* STM32L0xx/STM32F7xx ST headers difference.*/
+#if !defined(USART_ISR_LBDF)
+#define USART_ISR_LBDF USART_ISR_LBD
+#endif
+
+/* Handling differences in frame size bits.*/
+#if !defined(USART_CR1_M_0)
+#define USART_CR1_M_0 (1 << 12)
+#endif
+
+#if !defined(USART_CR1_M_1)
+#define USART_CR1_M_1 (1 << 28)
+#endif
+
+/* Workarounds for those devices where UARTs are USARTs.*/
+#if defined(USART4)
+#define UART4 USART4
+#endif
+#if defined(USART5)
+#define UART5 USART5
+#endif
+#if defined(USART7)
+#define UART7 USART7
+#endif
+#if defined(USART8)
+#define UART8 USART8
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief USART1 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+SerialDriver SD1;
+#endif
+
+/** @brief USART2 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+SerialDriver SD2;
+#endif
+
+/** @brief USART3 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+SerialDriver SD3;
+#endif
+
+/** @brief UART4 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+SerialDriver SD4;
+#endif
+
+/** @brief UART5 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+SerialDriver SD5;
+#endif
+
+/** @brief USART6 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+SerialDriver SD6;
+#endif
+
+/** @brief UART7 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+SerialDriver SD7;
+#endif
+
+/** @brief UART8 serial driver identifier.*/
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+SerialDriver SD8;
+#endif
+
+/** @brief LPUART1 serial driver identifier.*/
+#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__)
+SerialDriver LPSD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/** @brief Driver default configuration.*/
+static const SerialConfig default_config =
+{
+ SERIAL_DEFAULT_BITRATE,
+ 0,
+ USART_CR2_STOP1_BITS,
+ 0
+};
+
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD1.*/
+static uint8_t sd_in_buf1[STM32_SERIAL_USART1_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD1.*/
+static uint8_t sd_out_buf1[STM32_SERIAL_USART1_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD2.*/
+static uint8_t sd_in_buf2[STM32_SERIAL_USART2_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD2.*/
+static uint8_t sd_out_buf2[STM32_SERIAL_USART2_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD3.*/
+static uint8_t sd_in_buf3[STM32_SERIAL_USART3_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD3.*/
+static uint8_t sd_out_buf3[STM32_SERIAL_USART3_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD4.*/
+static uint8_t sd_in_buf4[STM32_SERIAL_UART4_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD4.*/
+static uint8_t sd_out_buf4[STM32_SERIAL_UART4_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD5.*/
+static uint8_t sd_in_buf5[STM32_SERIAL_UART5_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD5.*/
+static uint8_t sd_out_buf5[STM32_SERIAL_UART5_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD6.*/
+static uint8_t sd_in_buf6[STM32_SERIAL_USART6_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD6.*/
+static uint8_t sd_out_buf6[STM32_SERIAL_USART6_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD7.*/
+static uint8_t sd_in_buf7[STM32_SERIAL_UART7_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD7.*/
+static uint8_t sd_out_buf7[STM32_SERIAL_UART7_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+/** @brief Input buffer for SD8.*/
+static uint8_t sd_in_buf8[STM32_SERIAL_UART8_IN_BUF_SIZE];
+
+/** @brief Output buffer for SD8.*/
+static uint8_t sd_out_buf8[STM32_SERIAL_UART8_OUT_BUF_SIZE];
+#endif
+
+#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__)
+/** @brief Input buffer for LPSD1.*/
+static uint8_t sd_in_buflp1[STM32_SERIAL_LPUART1_IN_BUF_SIZE];
+
+/** @brief Output buffer for LPSD1.*/
+static uint8_t sd_out_buflp1[STM32_SERIAL_LPUART1_OUT_BUF_SIZE];
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief USART initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration
+ */
+static void usart_init(SerialDriver *sdp, const SerialConfig *config) {
+ uint32_t brr;
+ USART_TypeDef *u = sdp->usart;
+
+ /* Baud rate setting.*/
+#if STM32_SERIAL_USE_LPUART1
+ if (sdp == &LPSD1) {
+ osalDbgAssert((sdp->clock >= config->speed * 3U) &&
+ (sdp->clock <= config->speed * 4096U),
+ "invalid baud rate vs input clock");
+
+ brr = (uint32_t)(((uint64_t)sdp->clock * 256) / config->speed);
+
+ osalDbgAssert((brr >= 0x300) && (brr < 0x100000), "invalid BRR value");
+ }
+ else
+#endif
+ {
+ brr = (uint32_t)(sdp->clock / config->speed);
+
+ /* Correcting BRR value when oversampling by 8 instead of 16.
+ Fraction is still 4 bits wide, but only lower 3 bits used.
+ Mantissa is doubled, but Fraction is left the same.*/
+ if (config->cr1 & USART_CR1_OVER8)
+ brr = ((brr & ~7) * 2) | (brr & 7);
+
+ osalDbgAssert(brr < 0x10000, "invalid BRR value");
+ }
+ u->BRR = brr;
+
+ /* Note that some bits are enforced.*/
+ u->CR2 = config->cr2 | USART_CR2_LBDIE;
+ u->CR3 = config->cr3 | USART_CR3_EIE;
+ u->CR1 = config->cr1 | USART_CR1_UE | USART_CR1_PEIE |
+ USART_CR1_RXNEIE | USART_CR1_TE |
+ USART_CR1_RE;
+ u->ICR = 0xFFFFFFFFU;
+
+ /* Deciding mask to be applied on the data register on receive, this is
+ required in order to mask out the parity bit.*/
+ if ((config->cr1 & USART_CR1_PCE) != 0U) {
+ switch (config->cr1 & (USART_CR1_M_1 | USART_CR1_M_0)) {
+ case 0:
+ sdp->rxmask = 0x7F;
+ break;
+ case USART_CR1_M_1:
+ sdp->rxmask = 0x3F;
+ break;
+ default:
+ sdp->rxmask = 0xFF;
+ }
+ }
+ else {
+ sdp->rxmask = 0xFF;
+ }
+}
+
+/**
+ * @brief USART de-initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] u pointer to an USART I/O block
+ */
+static void usart_deinit(USART_TypeDef *u) {
+
+ u->CR1 = 0;
+ u->CR2 = 0;
+ u->CR3 = 0;
+}
+
+/**
+ * @brief Error handling routine.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] isr USART ISR register value
+ */
+static void set_error(SerialDriver *sdp, uint32_t isr) {
+ eventflags_t sts = 0;
+
+ if (isr & USART_ISR_ORE)
+ sts |= SD_OVERRUN_ERROR;
+ if (isr & USART_ISR_PE)
+ sts |= SD_PARITY_ERROR;
+ if (isr & USART_ISR_FE)
+ sts |= SD_FRAMING_ERROR;
+ if (isr & USART_ISR_NE)
+ sts |= SD_NOISE_ERROR;
+ osalSysLockFromISR();
+ chnAddFlagsI(sdp, sts);
+ osalSysUnlockFromISR();
+}
+
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+static void notify1(io_queue_t *qp) {
+
+ (void)qp;
+ USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+static void notify2(io_queue_t *qp) {
+
+ (void)qp;
+ USART2->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+static void notify3(io_queue_t *qp) {
+
+ (void)qp;
+ USART3->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+static void notify4(io_queue_t *qp) {
+
+ (void)qp;
+ UART4->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+static void notify5(io_queue_t *qp) {
+
+ (void)qp;
+ UART5->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+static void notify6(io_queue_t *qp) {
+
+ (void)qp;
+ USART6->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+static void notify7(io_queue_t *qp) {
+
+ (void)qp;
+ UART7->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+static void notify8(io_queue_t *qp) {
+
+ (void)qp;
+ UART8->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__)
+static void notifylp1(io_queue_t *qp) {
+
+ (void)qp;
+ LPUART1->CR1 |= USART_CR1_TXEIE | USART_CR1_TCIE;
+}
+#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_SERIAL_USE_USART1 || defined(__DOXYGEN__)
+#if !defined(STM32_USART1_SUPPRESS_ISR)
+#if !defined(STM32_USART1_HANDLER)
+#error "STM32_USART1_HANDLER not defined"
+#endif
+/**
+ * @brief USART1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_USART2 || defined(__DOXYGEN__)
+#if !defined(STM32_USART2_SUPPRESS_ISR)
+#if !defined(STM32_USART2_HANDLER)
+#error "STM32_USART2_HANDLER not defined"
+#endif
+/**
+ * @brief USART2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_USART3 || defined(__DOXYGEN__)
+#if !defined(STM32_USART3_SUPPRESS_ISR)
+#if !defined(STM32_USART3_HANDLER)
+#error "STM32_USART3_HANDLER not defined"
+#endif
+/**
+ * @brief USART3 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+#if !defined(STM32_UART4_SUPPRESS_ISR)
+#if !defined(STM32_UART4_HANDLER)
+#error "STM32_UART4_HANDLER not defined"
+#endif
+/**
+ * @brief UART4 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+#if !defined(STM32_UART5_SUPPRESS_ISR)
+#if !defined(STM32_UART5_HANDLER)
+#error "STM32_UART5_HANDLER not defined"
+#endif
+/**
+ * @brief UART5 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+#if !defined(STM32_USART6_SUPPRESS_ISR)
+#if !defined(STM32_USART6_HANDLER)
+#error "STM32_USART6_HANDLER not defined"
+#endif
+/**
+ * @brief USART6 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART7 || defined(__DOXYGEN__)
+#if !defined(STM32_UART7_SUPPRESS_ISR)
+#if !defined(STM32_UART7_HANDLER)
+#error "STM32_UART7_HANDLER not defined"
+#endif
+/**
+ * @brief UART7 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART8 || defined(__DOXYGEN__)
+#if !defined(STM32_UART8_SUPPRESS_ISR)
+#if !defined(STM32_UART8_HANDLER)
+#error "STM32_UART8_HANDLER not defined"
+#endif
+/**
+ * @brief UART8 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&SD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_SERIAL_USE_LPUART1 || defined(__DOXYGEN__)
+#if !defined(STM32_LPUART1_SUPPRESS_ISR)
+#if !defined(STM32_LPUART1_HANDLER)
+#error "STM32_LPUART1_HANDLER not defined"
+#endif
+/**
+ * @brief LPUART1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_LPUART1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ sd_lld_serve_interrupt(&LPSD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level serial driver initialization.
+ *
+ * @notapi
+ */
+void sd_lld_init(void) {
+
+#if STM32_SERIAL_USE_USART1
+ sdObjectInit(&SD1);
+ iqObjectInit(&SD1.iqueue, sd_in_buf1, sizeof sd_in_buf1, NULL, &SD1);
+ oqObjectInit(&SD1.oqueue, sd_out_buf1, sizeof sd_out_buf1, notify1, &SD1);
+ SD1.usart = USART1;
+ SD1.clock = STM32_USART1CLK;
+#if !defined(STM32_USART1_SUPPRESS_ISR) && defined(STM32_USART1_NUMBER)
+ nvicEnableVector(STM32_USART1_NUMBER, STM32_SERIAL_USART1_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_USART2
+ sdObjectInit(&SD2);
+ iqObjectInit(&SD2.iqueue, sd_in_buf2, sizeof sd_in_buf2, NULL, &SD2);
+ oqObjectInit(&SD2.oqueue, sd_out_buf2, sizeof sd_out_buf2, notify2, &SD2);
+ SD2.usart = USART2;
+ SD2.clock = STM32_USART2CLK;
+#if !defined(STM32_USART2_SUPPRESS_ISR) && defined(STM32_USART2_NUMBER)
+ nvicEnableVector(STM32_USART2_NUMBER, STM32_SERIAL_USART2_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_USART3
+ sdObjectInit(&SD3);
+ iqObjectInit(&SD3.iqueue, sd_in_buf3, sizeof sd_in_buf3, NULL, &SD3);
+ oqObjectInit(&SD3.oqueue, sd_out_buf3, sizeof sd_out_buf3, notify3, &SD3);
+ SD3.usart = USART3;
+ SD3.clock = STM32_USART3CLK;
+#if !defined(STM32_USART3_SUPPRESS_ISR) && defined(STM32_USART3_NUMBER)
+ nvicEnableVector(STM32_USART3_NUMBER, STM32_SERIAL_USART3_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART4
+ sdObjectInit(&SD4);
+ iqObjectInit(&SD4.iqueue, sd_in_buf4, sizeof sd_in_buf4, NULL, &SD4);
+ oqObjectInit(&SD4.oqueue, sd_out_buf4, sizeof sd_out_buf4, notify4, &SD4);
+ SD4.usart = UART4;
+ SD4.clock = STM32_UART4CLK;
+#if !defined(STM32_UART4_SUPPRESS_ISR) && defined(STM32_UART4_NUMBER)
+ nvicEnableVector(STM32_UART4_NUMBER, STM32_SERIAL_UART4_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART5
+ sdObjectInit(&SD5);
+ iqObjectInit(&SD5.iqueue, sd_in_buf5, sizeof sd_in_buf5, NULL, &SD5);
+ oqObjectInit(&SD5.oqueue, sd_out_buf5, sizeof sd_out_buf5, notify5, &SD5);
+ SD5.usart = UART5;
+ SD5.clock = STM32_UART5CLK;
+#if !defined(STM32_UART5_SUPPRESS_ISR) && defined(STM32_UART5_NUMBER)
+ nvicEnableVector(STM32_UART5_NUMBER, STM32_SERIAL_UART5_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_USART6
+ sdObjectInit(&SD6);
+ iqObjectInit(&SD6.iqueue, sd_in_buf6, sizeof sd_in_buf6, NULL, &SD6);
+ oqObjectInit(&SD6.oqueue, sd_out_buf6, sizeof sd_out_buf6, notify6, &SD6);
+ SD6.usart = USART6;
+ SD6.clock = STM32_USART6CLK;
+#if !defined(STM32_USART6_SUPPRESS_ISR) && defined(STM32_USART6_NUMBER)
+ nvicEnableVector(STM32_USART6_NUMBER, STM32_SERIAL_USART6_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART7
+ sdObjectInit(&SD7);
+ iqObjectInit(&SD7.iqueue, sd_in_buf7, sizeof sd_in_buf7, NULL, &SD7);
+ oqObjectInit(&SD7.oqueue, sd_out_buf7, sizeof sd_out_buf7, notify7, &SD7);
+ SD7.usart = UART7;
+ SD7.clock = STM32_UART7CLK;
+#if !defined(STM32_UART7_SUPPRESS_ISR) && defined(STM32_UART7_NUMBER)
+ nvicEnableVector(STM32_UART7_NUMBER, STM32_SERIAL_UART7_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_UART8
+ sdObjectInit(&SD8);
+ iqObjectInit(&SD8.iqueue, sd_in_buf8, sizeof sd_in_buf8, NULL, &SD8);
+ oqObjectInit(&SD8.oqueue, sd_out_buf8, sizeof sd_out_buf8, notify8, &SD8);
+ SD8.usart = UART8;
+ SD8.clock = STM32_UART8CLK;
+#if !defined(STM32_UART8_SUPPRESS_ISR) && defined(STM32_UART8_NUMBER)
+ nvicEnableVector(STM32_UART8_NUMBER, STM32_SERIAL_UART8_PRIORITY);
+#endif
+#endif
+
+#if STM32_SERIAL_USE_LPUART1
+ sdObjectInit(&LPSD1);
+ iqObjectInit(&LPSD1.iqueue, sd_in_buflp1, sizeof sd_in_buflp1, NULL, &LPSD1);
+ oqObjectInit(&LPSD1.oqueue, sd_out_buflp1, sizeof sd_out_buflp1, notifylp1, &LPSD1);
+ LPSD1.usart = LPUART1;
+ LPSD1.clock = STM32_LPUART1CLK;
+#if !defined(STM32_LPUART1_SUPPRESS_ISR) && defined(STM32_LPUART1_NUMBER)
+ nvicEnableVector(STM32_LPUART1_NUMBER, STM32_SERIAL_LPUART1_PRIORITY);
+#endif
+#endif
+}
+
+/**
+ * @brief Low level serial driver configuration and (re)start.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration.
+ * If this parameter is set to @p NULL then a default
+ * configuration is used.
+ *
+ * @notapi
+ */
+void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
+
+ if (config == NULL)
+ config = &default_config;
+
+ if (sdp->state == SD_STOP) {
+#if STM32_SERIAL_USE_USART1
+ if (&SD1 == sdp) {
+ rccEnableUSART1(true);
+ }
+#endif
+#if STM32_SERIAL_USE_USART2
+ if (&SD2 == sdp) {
+ rccEnableUSART2(true);
+ }
+#endif
+#if STM32_SERIAL_USE_USART3
+ if (&SD3 == sdp) {
+ rccEnableUSART3(true);
+ }
+#endif
+#if STM32_SERIAL_USE_UART4
+ if (&SD4 == sdp) {
+ rccEnableUART4(true);
+ }
+#endif
+#if STM32_SERIAL_USE_UART5
+ if (&SD5 == sdp) {
+ rccEnableUART5(true);
+ }
+#endif
+#if STM32_SERIAL_USE_USART6
+ if (&SD6 == sdp) {
+ rccEnableUSART6(true);
+ }
+#endif
+#if STM32_SERIAL_USE_UART7
+ if (&SD7 == sdp) {
+ rccEnableUART7(true);
+ }
+#endif
+#if STM32_SERIAL_USE_UART8
+ if (&SD8 == sdp) {
+ rccEnableUART8(true);
+ }
+#endif
+#if STM32_SERIAL_USE_LPUART1
+ if (&LPSD1 == sdp) {
+ rccEnableLPUART1(true);
+ }
+#endif
+ }
+ usart_init(sdp, config);
+}
+
+/**
+ * @brief Low level serial driver stop.
+ * @details De-initializes the USART, stops the associated clock, resets the
+ * interrupt vector.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ *
+ * @notapi
+ */
+void sd_lld_stop(SerialDriver *sdp) {
+
+ if (sdp->state == SD_READY) {
+ /* UART is de-initialized then clocks are disabled.*/
+ usart_deinit(sdp->usart);
+
+#if STM32_SERIAL_USE_USART1
+ if (&SD1 == sdp) {
+ rccDisableUSART1();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_USART2
+ if (&SD2 == sdp) {
+ rccDisableUSART2();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_USART3
+ if (&SD3 == sdp) {
+ rccDisableUSART3();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART4
+ if (&SD4 == sdp) {
+ rccDisableUART4();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART5
+ if (&SD5 == sdp) {
+ rccDisableUART5();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_USART6
+ if (&SD6 == sdp) {
+ rccDisableUSART6();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART7
+ if (&SD7 == sdp) {
+ rccDisableUART7();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_UART8
+ if (&SD8 == sdp) {
+ rccDisableUART8();
+ return;
+ }
+#endif
+#if STM32_SERIAL_USE_LPUART1
+ if (&LPSD1 == sdp) {
+ rccDisableLPUART1();
+ return;
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Common IRQ handler.
+ *
+ * @param[in] sdp communication channel associated to the USART
+ */
+void sd_lld_serve_interrupt(SerialDriver *sdp) {
+ USART_TypeDef *u = sdp->usart;
+ uint32_t cr1 = u->CR1;
+ uint32_t isr;
+
+ /* Reading and clearing status.*/
+ isr = u->ISR;
+ u->ICR = isr;
+
+ /* Error condition detection.*/
+ if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE))
+ set_error(sdp, isr);
+
+ /* Special case, LIN break detection.*/
+ if (isr & USART_ISR_LBDF) {
+ osalSysLockFromISR();
+ chnAddFlagsI(sdp, SD_BREAK_DETECTED);
+ osalSysUnlockFromISR();
+ }
+
+ /* Data available, note it is a while in order to handle two situations:
+ 1) Another byte arrived after removing the previous one, this would cause
+ an extra interrupt to serve.
+ 2) FIFO mode is enabled on devices that support it, we need to empty
+ the FIFO.*/
+ while (isr & USART_ISR_RXNE) {
+ osalSysLockFromISR();
+ sdIncomingDataI(sdp, (uint8_t)u->RDR & sdp->rxmask);
+ osalSysUnlockFromISR();
+
+ isr = u->ISR;
+ }
+
+ /* Transmission buffer empty, note it is a while in order to handle two
+ situations:
+ 1) The data registers has been emptied immediately after writing it, this
+ would cause an extra interrupt to serve.
+ 2) FIFO mode is enabled on devices that support it, we need to fill
+ the FIFO.*/
+ if (cr1 & USART_CR1_TXEIE) {
+ while (isr & USART_ISR_TXE) {
+ msg_t b;
+
+ osalSysLockFromISR();
+ b = oqGetI(&sdp->oqueue);
+ if (b < MSG_OK) {
+ chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
+ u->CR1 = cr1 & ~USART_CR1_TXEIE;
+ osalSysUnlockFromISR();
+ break;
+ }
+ u->TDR = b;
+ osalSysUnlockFromISR();
+
+ isr = u->ISR;
+ }
+ }
+
+ /* Physical transmission end.*/
+ if ((cr1 & USART_CR1_TCIE) && (isr & USART_ISR_TC)) {
+ osalSysLockFromISR();
+ if (oqIsEmptyI(&sdp->oqueue)) {
+ chnAddFlagsI(sdp, CHN_TRANSMISSION_END);
+ u->CR1 = cr1 & ~USART_CR1_TCIE;
+ }
+ osalSysUnlockFromISR();
+ }
+}
+
+#endif /* HAL_USE_SERIAL */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h new file mode 100644 index 0000000..19ee329 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.h @@ -0,0 +1,534 @@ +/*
+ 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 USARTv2/hal_serial_lld.h
+ * @brief STM32 low level serial driver header.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#ifndef HAL_SERIAL_LLD_H
+#define HAL_SERIAL_LLD_H
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Advanced buffering support switch.
+ * @details This constants enables the advanced buffering support in the
+ * low level driver, the queue buffer is no more part of the
+ * @p SerialDriver structure, each driver can have a different
+ * queue size.
+ */
+#define SERIAL_ADVANCED_BUFFERING_SUPPORT TRUE
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief USART1 driver enable switch.
+ * @details If set to @p TRUE the support for USART1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART1) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART1 FALSE
+#endif
+
+/**
+ * @brief USART2 driver enable switch.
+ * @details If set to @p TRUE the support for USART2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART2) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART2 FALSE
+#endif
+
+/**
+ * @brief USART3 driver enable switch.
+ * @details If set to @p TRUE the support for USART3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART3) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART3 FALSE
+#endif
+
+/**
+ * @brief UART4 driver enable switch.
+ * @details If set to @p TRUE the support for UART4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART4) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART4 FALSE
+#endif
+
+/**
+ * @brief UART5 driver enable switch.
+ * @details If set to @p TRUE the support for UART5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART5) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART5 FALSE
+#endif
+
+/**
+ * @brief USART6 driver enable switch.
+ * @details If set to @p TRUE the support for USART6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_USART6) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART6 FALSE
+#endif
+
+/**
+ * @brief UART7 driver enable switch.
+ * @details If set to @p TRUE the support for UART7 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART7) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART7 FALSE
+#endif
+
+/**
+ * @brief UART8 driver enable switch.
+ * @details If set to @p TRUE the support for UART8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_UART8) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_UART8 FALSE
+#endif
+
+/**
+ * @brief LPUART1 driver enable switch.
+ * @details If set to @p TRUE the support for LPUART is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_SERIAL_USE_LPUART1) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_LPUART1 FALSE
+#endif
+
+/**
+ * @brief USART1 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART1_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART1_PRIORITY 12
+#endif
+
+/**
+ * @brief USART2 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART2_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART2_PRIORITY 12
+#endif
+
+/**
+ * @brief USART3 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART3_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART3_PRIORITY 12
+#endif
+
+/**
+ * @brief UART4 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART4_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART4_PRIORITY 12
+#endif
+
+/**
+ * @brief UART5 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART5_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART5_PRIORITY 12
+#endif
+
+/**
+ * @brief USART6 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART6_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART6_PRIORITY 12
+#endif
+
+/**
+ * @brief UART7 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART7_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART7_PRIORITY 12
+#endif
+
+/**
+ * @brief UART8 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_UART8_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART8_PRIORITY 12
+#endif
+
+/**
+ * @brief LPUART1 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_LPUART1_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_LPUART1_PRIORITY 12
+#endif
+
+/**
+ * @brief Input buffer size for USART1.
+ */
+#if !defined(STM32_SERIAL_USART1_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART1_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for USART1.
+ */
+#if !defined(STM32_SERIAL_USART1_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART1_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for USART2.
+ */
+#if !defined(STM32_SERIAL_USART2_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART2_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for USART2.
+ */
+#if !defined(STM32_SERIAL_USART2_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART2_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for USART3.
+ */
+#if !defined(STM32_SERIAL_USART3_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART3_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for USART3.
+ */
+#if !defined(STM32_SERIAL_USART3_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART3_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for UART4.
+ */
+#if !defined(STM32_SERIAL_UART4_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART4_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for UART4.
+ */
+#if !defined(STM32_SERIAL_UART4_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART4_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for UART5.
+ */
+#if !defined(STM32_SERIAL_UART5_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART5_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for UART5.
+ */
+#if !defined(STM32_SERIAL_UART5_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART5_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for USART6.
+ */
+#if !defined(STM32_SERIAL_USART6_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART6_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for USART6.
+ */
+#if !defined(STM32_SERIAL_USART6_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART6_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for UART7.
+ */
+#if !defined(STM32_SERIAL_UART7_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART7_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for UART7.
+ */
+#if !defined(STM32_SERIAL_UART7_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART7_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for UART8.
+ */
+#if !defined(STM32_SERIAL_UART8_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART8_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for UART8.
+ */
+#if !defined(STM32_SERIAL_UART8_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_UART8_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Input buffer size for LPUART1.
+ */
+#if !defined(STM32_SERIAL_LPUART1_IN_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_LPUART1_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+
+/**
+ * @brief Output buffer size for LPUART1.
+ */
+#if !defined(STM32_SERIAL_LPUART1_OUT_BUF_SIZE) || defined(__DOXYGEN__)
+#define STM32_SERIAL_LPUART1_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_SERIAL_USE_USART1 && !STM32_HAS_USART1
+#error "USART1 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_USART2 && !STM32_HAS_USART2
+#error "USART2 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_USART3 && !STM32_HAS_USART3
+#error "USART3 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART4 && !STM32_HAS_UART4
+#error "UART4 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART5 && !STM32_HAS_UART5
+#error "UART5 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_USART6 && !STM32_HAS_USART6
+#error "USART6 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART7 && !STM32_HAS_UART7
+#error "UART7 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_UART8 && !STM32_HAS_UART8
+#error "UART8 not present in the selected device"
+#endif
+
+#if STM32_SERIAL_USE_LPUART1 && !STM32_HAS_LPUART1
+#error "LPUART1 not present in the selected device"
+#endif
+
+#if !STM32_SERIAL_USE_USART1 && !STM32_SERIAL_USE_USART2 && \
+ !STM32_SERIAL_USE_USART3 && !STM32_SERIAL_USE_UART4 && \
+ !STM32_SERIAL_USE_UART5 && !STM32_SERIAL_USE_USART6 && \
+ !STM32_SERIAL_USE_UART7 && !STM32_SERIAL_USE_UART8 && \
+ !STM32_SERIAL_USE_LPUART1
+#error "SERIAL driver activated but no USART/UART peripheral assigned"
+#endif
+
+#if !defined(STM32_USART1_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_USART1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART1_PRIORITY)
+#error "Invalid IRQ priority assigned to USART1"
+#endif
+
+#if !defined(STM32_USART2_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_USART2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART2_PRIORITY)
+#error "Invalid IRQ priority assigned to USART2"
+#endif
+
+#if !defined(STM32_USART3_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_USART3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART3_PRIORITY)
+#error "Invalid IRQ priority assigned to USART3"
+#endif
+
+#if !defined(STM32_UART4_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_UART4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART4_PRIORITY)
+#error "Invalid IRQ priority assigned to UART4"
+#endif
+
+#if !defined(STM32_UART5_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_UART5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART5_PRIORITY)
+#error "Invalid IRQ priority assigned to UART5"
+#endif
+
+#if !defined(STM32_USART6_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_USART6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_USART6_PRIORITY)
+#error "Invalid IRQ priority assigned to USART6"
+#endif
+
+#if !defined(STM32_UART7_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_UART7 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART7_PRIORITY)
+#error "Invalid IRQ priority assigned to UART7"
+#endif
+
+#if !defined(STM32_UART8_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_UART8 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_UART8_PRIORITY)
+#error "Invalid IRQ priority assigned to UART8"
+#endif
+
+#if !defined(STM32_LPUART1_SUPPRESS_ISR) && \
+ STM32_SERIAL_USE_LPUART1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SERIAL_LPUART1_PRIORITY)
+#error "Invalid IRQ priority assigned to LPUART1"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 Serial Driver configuration structure.
+ * @details An instance of this structure must be passed to @p sdStart()
+ * in order to configure and start a serial driver operations.
+ * @note This structure content is architecture dependent, each driver
+ * implementation defines its own version and the custom static
+ * initializers.
+ */
+typedef struct {
+ /**
+ * @brief Bit rate.
+ */
+ uint32_t speed;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Initialization value for the CR1 register.
+ */
+ uint32_t cr1;
+ /**
+ * @brief Initialization value for the CR2 register.
+ */
+ uint32_t cr2;
+ /**
+ * @brief Initialization value for the CR3 register.
+ */
+ uint32_t cr3;
+} SerialConfig;
+
+/**
+ * @brief @p SerialDriver specific data.
+ */
+#define _serial_driver_data \
+ _base_asynchronous_channel_data \
+ /* Driver state.*/ \
+ sdstate_t state; \
+ /* Input queue.*/ \
+ input_queue_t iqueue; \
+ /* Output queue.*/ \
+ output_queue_t oqueue; \
+ /* End of the mandatory fields.*/ \
+ /* Pointer to the USART registers block.*/ \
+ USART_TypeDef *usart; \
+ /* Clock frequency for the associated USART/UART.*/ \
+ uint32_t clock; \
+ /* Mask to be applied on received frames.*/ \
+ uint8_t rxmask;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*
+ * Extra USARTs definitions here (missing from the ST header file).
+ */
+#define USART_CR2_STOP1_BITS (0 << 12) /**< @brief CR2 1 stop bit value.*/
+#define USART_CR2_STOP0P5_BITS (1 << 12) /**< @brief CR2 0.5 stop bit value.*/
+#define USART_CR2_STOP2_BITS (2 << 12) /**< @brief CR2 2 stop bit value.*/
+#define USART_CR2_STOP1P5_BITS (3 << 12) /**< @brief CR2 1.5 stop bit value.*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_SERIAL_USE_USART1 && !defined(__DOXYGEN__)
+extern SerialDriver SD1;
+#endif
+#if STM32_SERIAL_USE_USART2 && !defined(__DOXYGEN__)
+extern SerialDriver SD2;
+#endif
+#if STM32_SERIAL_USE_USART3 && !defined(__DOXYGEN__)
+extern SerialDriver SD3;
+#endif
+#if STM32_SERIAL_USE_UART4 && !defined(__DOXYGEN__)
+extern SerialDriver SD4;
+#endif
+#if STM32_SERIAL_USE_UART5 && !defined(__DOXYGEN__)
+extern SerialDriver SD5;
+#endif
+#if STM32_SERIAL_USE_USART6 && !defined(__DOXYGEN__)
+extern SerialDriver SD6;
+#endif
+#if STM32_SERIAL_USE_UART7 && !defined(__DOXYGEN__)
+extern SerialDriver SD7;
+#endif
+#if STM32_SERIAL_USE_UART8 && !defined(__DOXYGEN__)
+extern SerialDriver SD8;
+#endif
+#if STM32_SERIAL_USE_LPUART1 && !defined(__DOXYGEN__)
+extern SerialDriver LPSD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sd_lld_init(void);
+ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
+ void sd_lld_stop(SerialDriver *sdp);
+ void sd_lld_serve_interrupt(SerialDriver *sdp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SERIAL */
+
+#endif /* HAL_SERIAL_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c new file mode 100644 index 0000000..3787716 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.c @@ -0,0 +1,1075 @@ +/*
+ 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 USARTv2/hal_uart_lld.c
+ * @brief STM32 low level UART driver code.
+ *
+ * @addtogroup UART
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_UART || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* For compatibility for those devices without LIN support in the USARTs.*/
+#if !defined(USART_ISR_LBDF)
+#define USART_ISR_LBDF 0
+#endif
+
+#if !defined(USART_CR2_LBDIE)
+#define USART_CR2_LBDIE 0
+#endif
+
+/* STM32L0xx/STM32F7xx ST headers difference.*/
+#if !defined(USART_ISR_LBDF)
+#define USART_ISR_LBDF USART_ISR_LBD
+#endif
+
+/* STM32L0xx/STM32F7xx ST headers difference.*/
+#if !defined(USART_ISR_LBDF)
+#define USART_ISR_LBDF USART_ISR_LBD
+#endif
+
+#define USART1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART1_RX_DMA_STREAM, \
+ STM32_USART1_RX_DMA_CHN)
+
+#define USART1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART1_TX_DMA_STREAM, \
+ STM32_USART1_TX_DMA_CHN)
+
+#define USART2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART2_RX_DMA_STREAM, \
+ STM32_USART2_RX_DMA_CHN)
+
+#define USART2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART2_TX_DMA_STREAM, \
+ STM32_USART2_TX_DMA_CHN)
+
+#define USART3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART3_RX_DMA_STREAM, \
+ STM32_USART3_RX_DMA_CHN)
+
+#define USART3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART3_TX_DMA_STREAM, \
+ STM32_USART3_TX_DMA_CHN)
+
+#define UART4_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART4_RX_DMA_STREAM, \
+ STM32_UART4_RX_DMA_CHN)
+
+#define UART4_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART4_TX_DMA_STREAM, \
+ STM32_UART4_TX_DMA_CHN)
+
+#define UART5_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART5_RX_DMA_STREAM, \
+ STM32_UART5_RX_DMA_CHN)
+
+#define UART5_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART5_TX_DMA_STREAM, \
+ STM32_UART5_TX_DMA_CHN)
+
+#define USART6_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART6_RX_DMA_STREAM, \
+ STM32_USART6_RX_DMA_CHN)
+
+#define USART6_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART6_TX_DMA_STREAM, \
+ STM32_USART6_TX_DMA_CHN)
+
+#define UART7_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART7_RX_DMA_STREAM, \
+ STM32_UART7_RX_DMA_CHN)
+
+#define UART7_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART7_TX_DMA_STREAM, \
+ STM32_UART7_TX_DMA_CHN)
+
+#define UART8_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART8_RX_DMA_STREAM, \
+ STM32_UART8_RX_DMA_CHN)
+
+#define UART8_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_UART8_TX_DMA_STREAM, \
+ STM32_UART8_TX_DMA_CHN)
+
+/* Workarounds for those devices where UARTs are USARTs.*/
+#if defined(USART4)
+#define UART4 USART4
+#endif
+#if defined(USART5)
+#define UART5 USART5
+#endif
+#if defined(USART7)
+#define UART7 USART7
+#endif
+#if defined(USART8)
+#define UART8 USART8
+#endif
+
+/* Workaround for more differences in headers.*/
+#if !defined(USART_CR1_M0)
+#define USART_CR1_M0 USART_CR1_M
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief USART1 UART driver identifier.*/
+#if STM32_UART_USE_USART1 || defined(__DOXYGEN__)
+UARTDriver UARTD1;
+#endif
+
+/** @brief USART2 UART driver identifier.*/
+#if STM32_UART_USE_USART2 || defined(__DOXYGEN__)
+UARTDriver UARTD2;
+#endif
+
+/** @brief USART3 UART driver identifier.*/
+#if STM32_UART_USE_USART3 || defined(__DOXYGEN__)
+UARTDriver UARTD3;
+#endif
+
+/** @brief UART4 UART driver identifier.*/
+#if STM32_UART_USE_UART4 || defined(__DOXYGEN__)
+UARTDriver UARTD4;
+#endif
+
+/** @brief UART5 UART driver identifier.*/
+#if STM32_UART_USE_UART5 || defined(__DOXYGEN__)
+UARTDriver UARTD5;
+#endif
+
+/** @brief USART6 UART driver identifier.*/
+#if STM32_UART_USE_USART6 || defined(__DOXYGEN__)
+UARTDriver UARTD6;
+#endif
+
+/** @brief UART7 UART driver identifier.*/
+#if STM32_UART_USE_UART7 || defined(__DOXYGEN__)
+UARTDriver UARTD7;
+#endif
+
+/** @brief UART8 UART driver identifier.*/
+#if STM32_UART_USE_UART8 || defined(__DOXYGEN__)
+UARTDriver UARTD8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Status bits translation.
+ *
+ * @param[in] isr USART SR register value
+ *
+ * @return The error flags.
+ */
+static uartflags_t translate_errors(uint32_t isr) {
+ uartflags_t sts = 0;
+
+ if (isr & USART_ISR_ORE)
+ sts |= UART_OVERRUN_ERROR;
+ if (isr & USART_ISR_PE)
+ sts |= UART_PARITY_ERROR;
+ if (isr & USART_ISR_FE)
+ sts |= UART_FRAMING_ERROR;
+ if (isr & USART_ISR_NE)
+ sts |= UART_NOISE_ERROR;
+ if (isr & USART_ISR_LBDF)
+ sts |= UART_BREAK_DETECTED;
+ return sts;
+}
+
+/**
+ * @brief Puts the receiver in the UART_RX_IDLE state.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
+ uint32_t mode;
+
+ /* RX DMA channel preparation, if the char callback is defined then the
+ TCIE interrupt is enabled too.*/
+ if (uartp->config->rxchar_cb == NULL)
+ mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC;
+ else
+ mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE;
+ dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf);
+ dmaStreamSetTransactionSize(uartp->dmarx, 1);
+ dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | mode);
+ dmaStreamEnable(uartp->dmarx);
+}
+
+/**
+ * @brief USART de-initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void usart_stop(UARTDriver *uartp) {
+
+ /* Stops RX and TX DMA channels.*/
+ dmaStreamDisable(uartp->dmarx);
+ dmaStreamDisable(uartp->dmatx);
+
+ /* Stops USART operations.*/
+ uartp->usart->CR1 = 0;
+ uartp->usart->CR2 = 0;
+ uartp->usart->CR3 = 0;
+}
+
+/**
+ * @brief USART initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+static void usart_start(UARTDriver *uartp) {
+ uint32_t fck;
+ uint32_t cr1;
+ const uint32_t tmo = uartp->config->timeout;
+ USART_TypeDef *u = uartp->usart;
+
+ /* Defensive programming, starting from a clean state.*/
+ usart_stop(uartp);
+
+ /* Baud rate setting.*/
+ fck = (uint32_t)(uartp->clock / uartp->config->speed);
+
+ /* Correcting USARTDIV when oversampling by 8 instead of 16.
+ Fraction is still 4 bits wide, but only lower 3 bits used.
+ Mantissa is doubled, but Fraction is left the same.*/
+ if (uartp->config->cr1 & USART_CR1_OVER8)
+ fck = ((fck & ~7) * 2) | (fck & 7);
+ u->BRR = fck;
+
+ /* Resetting eventual pending status flags.*/
+ u->ICR = 0xFFFFFFFFU;
+
+ /* Note that some bits are enforced because required for correct driver
+ operations.*/
+ u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE;
+ u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR |
+ USART_CR3_EIE;
+
+ /* Mustn't ever set TCIE here - if done, it causes an immediate
+ interrupt.*/
+ cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
+ u->CR1 = uartp->config->cr1 | cr1;
+
+ /* Set receive timeout and checks if it is really applied.*/
+ if (tmo > 0) {
+ osalDbgAssert(tmo <= USART_RTOR_RTO, "Timeout overflow");
+ u->RTOR = tmo;
+ osalDbgAssert(tmo == u->RTOR, "Timeout feature unsupported in this UART");
+ }
+
+ /* Starting the receiver idle loop.*/
+ uart_enter_rx_idle_loop(uartp);
+}
+
+/**
+ * @brief RX DMA common service routine.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_UART_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_UART_DMA_ERROR_HOOK(uartp);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (uartp->rxstate == UART_RX_IDLE) {
+ /* Receiver in idle state, a callback is generated, if enabled, for each
+ received character and then the driver stays in the same state.*/
+ _uart_rx_idle_code(uartp);
+ }
+ else {
+ /* Receiver in active state, a callback is generated, if enabled, after
+ a completed transfer.*/
+ dmaStreamDisable(uartp->dmarx);
+ _uart_rx_complete_isr_code(uartp);
+ }
+}
+
+/**
+ * @brief TX DMA common service routine.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_UART_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_UART_DMA_ERROR_HOOK(uartp);
+ }
+#else
+ (void)flags;
+#endif
+
+ dmaStreamDisable(uartp->dmatx);
+
+ /* A callback is generated, if enabled, after a completed transfer.*/
+ _uart_tx1_isr_code(uartp);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_UART_USE_USART1 || defined(__DOXYGEN__)
+#if !defined(STM32_USART1_SUPPRESS_ISR)
+#if !defined(STM32_USART1_HANDLER)
+#error "STM32_USART1_HANDLER not defined"
+#endif
+/**
+ * @brief USART1 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_USART2 || defined(__DOXYGEN__)
+#if !defined(STM32_USART2_SUPPRESS_ISR)
+#if !defined(STM32_USART2_HANDLER)
+#error "STM32_USART2_HANDLER not defined"
+#endif
+/**
+ * @brief USART2 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_USART3 || defined(__DOXYGEN__)
+#if !defined(STM32_USART3_SUPPRESS_ISR)
+#if !defined(STM32_USART3_HANDLER)
+#error "STM32_USART3_HANDLER not defined"
+#endif
+/**
+ * @brief USART3 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_UART4 || defined(__DOXYGEN__)
+#if !defined(STM32_UART4_SUPPRESS_ISR)
+#if !defined(STM32_UART4_HANDLER)
+#error "STM32_UART4_HANDLER not defined"
+#endif
+/**
+ * @brief UART4 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_UART5 || defined(__DOXYGEN__)
+#if !defined(STM32_UART5_SUPPRESS_ISR)
+#if !defined(STM32_UART5_HANDLER)
+#error "STM32_UART5_HANDLER not defined"
+#endif
+/**
+ * @brief UART5 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_USART6 || defined(__DOXYGEN__)
+#if !defined(STM32_USART6_SUPPRESS_ISR)
+#if !defined(STM32_USART6_HANDLER)
+#error "STM32_USART6_HANDLER not defined"
+#endif
+/**
+ * @brief USART6 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_UART7 || defined(__DOXYGEN__)
+#if !defined(STM32_UART7_SUPPRESS_ISR)
+#if !defined(STM32_UART7_HANDLER)
+#error "STM32_UART7_HANDLER not defined"
+#endif
+/**
+ * @brief UART7 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+#if STM32_UART_USE_UART8 || defined(__DOXYGEN__)
+#if !defined(STM32_UART8_SUPPRESS_ISR)
+#if !defined(STM32_UART8_HANDLER)
+#error "STM32_UART8_HANDLER not defined"
+#endif
+/**
+ * @brief UART8 IRQ handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ uart_lld_serve_interrupt(&UARTD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level UART driver initialization.
+ *
+ * @notapi
+ */
+void uart_lld_init(void) {
+
+#if STM32_UART_USE_USART1
+ uartObjectInit(&UARTD1);
+ UARTD1.usart = USART1;
+ UARTD1.clock = STM32_USART1CLK;
+ UARTD1.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD1.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD1.dmarx = NULL;
+ UARTD1.dmatx = NULL;
+#if !defined(STM32_USART1_SUPPRESS_ISR) && defined(STM32_USART1_NUMBER)
+ nvicEnableVector(STM32_USART1_NUMBER, STM32_UART_USART1_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_USART2
+ uartObjectInit(&UARTD2);
+ UARTD2.usart = USART2;
+ UARTD2.clock = STM32_USART2CLK;
+ UARTD2.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD2.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD2.dmarx = NULL;
+ UARTD2.dmatx = NULL;
+#if !defined(STM32_USART2_SUPPRESS_ISR) && defined(STM32_USART2_NUMBER)
+ nvicEnableVector(STM32_USART2_NUMBER, STM32_UART_USART2_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_USART3
+ uartObjectInit(&UARTD3);
+ UARTD3.usart = USART3;
+ UARTD3.clock = STM32_USART3CLK;
+ UARTD3.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD3.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD3.dmarx = NULL;
+ UARTD3.dmatx = NULL;
+#if !defined(STM32_USART3_SUPPRESS_ISR) && defined(STM32_USART3_NUMBER)
+ nvicEnableVector(STM32_USART3_NUMBER, STM32_UART_USART3_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_UART4
+ uartObjectInit(&UARTD4);
+ UARTD4.usart = UART4;
+ UARTD4.clock = STM32_UART4CLK;
+ UARTD4.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD4.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD4.dmarx = NULL;
+ UARTD4.dmatx = NULL;
+#if !defined(STM32_UART4_SUPPRESS_ISR) && defined(STM32_UART4_NUMBER)
+ nvicEnableVector(STM32_UART4_NUMBER, STM32_UART_UART4_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_UART5
+ uartObjectInit(&UARTD5);
+ UARTD5.usart = UART5;
+ UARTD5.clock = STM32_UART5CLK;
+ UARTD5.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD5.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD5.dmarx = NULL;
+ UARTD5.dmatx = NULL;
+#if !defined(STM32_UART5_SUPPRESS_ISR) && defined(STM32_UART5_NUMBER)
+ nvicEnableVector(STM32_UART5_NUMBER, STM32_UART_UART5_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_USART6
+ uartObjectInit(&UARTD6);
+ UARTD6.usart = USART6;
+ UARTD6.clock = STM32_USART6CLK;
+ UARTD6.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD6.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD6.dmarx = NULL;
+ UARTD6.dmatx = NULL;
+#if !defined(STM32_USART6_SUPPRESS_ISR) && defined(STM32_USART6_NUMBER)
+ nvicEnableVector(STM32_USART6_NUMBER, STM32_UART_USART6_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_UART7
+ uartObjectInit(&UARTD7);
+ UARTD7.usart = UART7;
+ UARTD7.clock = STM32_UART7CLK;
+ UARTD7.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD7.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD7.dmarx = NULL;
+ UARTD7.dmatx = NULL;
+#if !defined(STM32_UART7_SUPPRESS_ISR) && defined(STM32_UART7_NUMBER)
+ nvicEnableVector(STM32_UART7_NUMBER, STM32_UART_UART7_IRQ_PRIORITY);
+#endif
+#endif
+
+#if STM32_UART_USE_UART8
+ uartObjectInit(&UARTD8);
+ UARTD8.usart = UART8;
+ UARTD8.clock = STM32_UART8CLK;
+ UARTD8.dmarxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD8.dmatxmode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+ UARTD8.dmarx = NULL;
+ UARTD8.dmatx = NULL;
+#if !defined(STM32_UART8_SUPPRESS_ISR) && defined(STM32_UART8_NUMBER)
+ nvicEnableVector(STM32_UART8_NUMBER, STM32_UART_UART8_IRQ_PRIORITY);
+#endif
+#endif
+}
+
+/**
+ * @brief Configures and activates the UART peripheral.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+void uart_lld_start(UARTDriver *uartp) {
+
+ if (uartp->state == UART_STOP) {
+#if STM32_UART_USE_USART1
+ if (&UARTD1 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART1_RX_DMA_STREAM,
+ STM32_UART_USART1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART1_TX_DMA_STREAM,
+ STM32_UART_USART1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART1(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART1_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART1_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_USART2
+ if (&UARTD2 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART2_RX_DMA_STREAM,
+ STM32_UART_USART2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART2_TX_DMA_STREAM,
+ STM32_UART_USART2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART2(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART2_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART2_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_USART3
+ if (&UARTD3 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART3_RX_DMA_STREAM,
+ STM32_UART_USART3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART3_TX_DMA_STREAM,
+ STM32_UART_USART3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART3(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART3_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART3_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_UART4
+ if (&UARTD4 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART4_RX_DMA_STREAM,
+ STM32_UART_UART4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART4_TX_DMA_STREAM,
+ STM32_UART_UART4_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART4(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART4_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART4_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART4_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART4_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_UART5
+ if (&UARTD5 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART5_RX_DMA_STREAM,
+ STM32_UART_UART5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART5_TX_DMA_STREAM,
+ STM32_UART_UART5_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART5(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART5_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART5_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART5_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART5_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_USART6
+ if (&UARTD6 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_USART6_RX_DMA_STREAM,
+ STM32_UART_USART6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_USART6_TX_DMA_STREAM,
+ STM32_UART_USART6_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUSART6(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(USART6_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(USART6_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART6_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_USART6_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_USART6_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_UART7
+ if (&UARTD7 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART7_RX_DMA_STREAM,
+ STM32_UART_UART7_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART7_TX_DMA_STREAM,
+ STM32_UART_UART7_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART7(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART7_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART7_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART7_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART7_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART7_TX);
+#endif
+ }
+#endif
+
+#if STM32_UART_USE_UART8
+ if (&UARTD8 == uartp) {
+ uartp->dmarx = dmaStreamAllocI(STM32_UART_UART8_RX_DMA_STREAM,
+ STM32_UART_UART8_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmarx != NULL, "unable to allocate stream");
+ uartp->dmatx = dmaStreamAllocI(STM32_UART_UART8_TX_DMA_STREAM,
+ STM32_UART_UART8_IRQ_PRIORITY,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (void *)uartp);
+ osalDbgAssert(uartp->dmatx != NULL, "unable to allocate stream");
+
+ rccEnableUART8(true);
+ uartp->dmarxmode |= STM32_DMA_CR_CHSEL(UART8_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY);
+ uartp->dmatxmode |= STM32_DMA_CR_CHSEL(UART8_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_UART8_DMA_PRIORITY);
+#if STM32_DMA_SUPPORTS_DMAMUX
+ dmaSetRequestSource(uartp->dmarx, STM32_DMAMUX1_UART8_RX);
+ dmaSetRequestSource(uartp->dmatx, STM32_DMAMUX1_UART8_TX);
+#endif
+ }
+#endif
+
+ /* Static DMA setup, the transfer size depends on the USART settings,
+ it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/
+ if ((uartp->config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M0) {
+ uartp->dmarxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ uartp->dmatxmode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ }
+ dmaStreamSetPeripheral(uartp->dmarx, &uartp->usart->RDR);
+ dmaStreamSetPeripheral(uartp->dmatx, &uartp->usart->TDR);
+ uartp->rxbuf = 0;
+ }
+
+ uartp->rxstate = UART_RX_IDLE;
+ uartp->txstate = UART_TX_IDLE;
+ usart_start(uartp);
+}
+
+/**
+ * @brief Deactivates the UART peripheral.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+void uart_lld_stop(UARTDriver *uartp) {
+
+ if (uartp->state == UART_READY) {
+ usart_stop(uartp);
+ dmaStreamFreeI(uartp->dmarx);
+ dmaStreamFreeI(uartp->dmatx);
+ uartp->dmarx = NULL;
+ uartp->dmatx = NULL;
+
+#if STM32_UART_USE_USART1
+ if (&UARTD1 == uartp) {
+ rccDisableUSART1();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_USART2
+ if (&UARTD2 == uartp) {
+ rccDisableUSART2();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_USART3
+ if (&UARTD3 == uartp) {
+ rccDisableUSART3();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART4
+ if (&UARTD4 == uartp) {
+ rccDisableUART4();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART5
+ if (&UARTD5 == uartp) {
+ rccDisableUART5();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_USART6
+ if (&UARTD6 == uartp) {
+ rccDisableUSART6();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART7
+ if (&UARTD7 == uartp) {
+ rccDisableUART7();
+ return;
+ }
+#endif
+
+#if STM32_UART_USE_UART8
+ if (&UARTD8 == uartp) {
+ rccDisableUART8();
+ return;
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts a transmission on the UART peripheral.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] n number of data frames to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
+
+ /* TX DMA channel preparation.*/
+ dmaStreamSetMemory0(uartp->dmatx, txbuf);
+ dmaStreamSetTransactionSize(uartp->dmatx, n);
+ dmaStreamSetMode(uartp->dmatx, uartp->dmatxmode | STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);
+
+ /* Only enable TC interrupt if there's a callback attached to it or
+ if called from uartSendFullTimeout(). Also we need to clear TC flag
+ which could be set before.*/
+#if UART_USE_WAIT == TRUE
+ if ((uartp->config->txend2_cb != NULL) || (uartp->early == false)) {
+#else
+ if (uartp->config->txend2_cb != NULL) {
+#endif
+ uartp->usart->ICR = USART_ICR_TCCF;
+ uartp->usart->CR1 |= USART_CR1_TCIE;
+ }
+
+ /* Starting transfer.*/
+ dmaStreamEnable(uartp->dmatx);
+}
+
+/**
+ * @brief Stops any ongoing transmission.
+ * @note Stopping a transmission also suppresses the transmission callbacks.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @return The number of data frames not transmitted by the
+ * stopped transmit operation.
+ *
+ * @notapi
+ */
+size_t uart_lld_stop_send(UARTDriver *uartp) {
+
+ dmaStreamDisable(uartp->dmatx);
+
+ return dmaStreamGetTransactionSize(uartp->dmatx);
+}
+
+/**
+ * @brief Starts a receive operation on the UART peripheral.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] n number of data frames to send
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
+
+ /* Stopping previous activity (idle state).*/
+ dmaStreamDisable(uartp->dmarx);
+
+ /* RX DMA channel preparation.*/
+ dmaStreamSetMemory0(uartp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(uartp->dmarx, n);
+ dmaStreamSetMode(uartp->dmarx, uartp->dmarxmode | STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);
+
+ /* Starting transfer.*/
+ dmaStreamEnable(uartp->dmarx);
+}
+
+/**
+ * @brief Stops any ongoing receive operation.
+ * @note Stopping a receive operation also suppresses the receive callbacks.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @return The number of data frames not received by the
+ * stopped receive operation.
+ *
+ * @notapi
+ */
+size_t uart_lld_stop_receive(UARTDriver *uartp) {
+ size_t n;
+
+ dmaStreamDisable(uartp->dmarx);
+ n = dmaStreamGetTransactionSize(uartp->dmarx);
+ uart_enter_rx_idle_loop(uartp);
+
+ return n;
+}
+
+/**
+ * @brief USART common service routine.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+void uart_lld_serve_interrupt(UARTDriver *uartp) {
+ uint32_t isr;
+ USART_TypeDef *u = uartp->usart;
+ uint32_t cr1 = u->CR1;
+
+ /* Reading and clearing status.*/
+ isr = u->ISR;
+ u->ICR = isr;
+
+ if (isr & (USART_ISR_LBDF | USART_ISR_ORE | USART_ISR_NE |
+ USART_ISR_FE | USART_ISR_PE)) {
+ _uart_rx_error_isr_code(uartp, translate_errors(isr));
+ }
+
+ if ((isr & USART_ISR_TC) && (cr1 & USART_CR1_TCIE)) {
+ /* TC interrupt disabled.*/
+ u->CR1 = cr1 & ~USART_CR1_TCIE;
+
+ /* End of transmission, a callback is generated.*/
+ _uart_tx2_isr_code(uartp);
+ }
+
+ /* Timeout interrupt sources are only checked if enabled in CR1.*/
+ if (((cr1 & USART_CR1_IDLEIE) && (isr & USART_ISR_IDLE)) ||
+ ((cr1 & USART_CR1_RTOIE) && (isr & USART_ISR_RTOF))) {
+ _uart_timeout_isr_code(uartp);
+ }
+}
+
+#endif /* HAL_USE_UART */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h new file mode 100644 index 0000000..ec5a694 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/hal_uart_lld.h @@ -0,0 +1,842 @@ +/*
+ 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 USARTv2/hal_uart_lld.h
+ * @brief STM32 low level UART driver header.
+ *
+ * @addtogroup UART
+ * @{
+ */
+
+#ifndef HAL_UART_LLD_H
+#define HAL_UART_LLD_H
+
+#if HAL_USE_UART || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief UART driver on USART1 enable switch.
+ * @details If set to @p TRUE the support for USART1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART1) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART1 FALSE
+#endif
+
+/**
+ * @brief UART driver on USART2 enable switch.
+ * @details If set to @p TRUE the support for USART2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART2) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART2 FALSE
+#endif
+
+/**
+ * @brief UART driver on USART3 enable switch.
+ * @details If set to @p TRUE the support for USART3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART3) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART3 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART4 enable switch.
+ * @details If set to @p TRUE the support for UART4 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART4) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART4 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART5 enable switch.
+ * @details If set to @p TRUE the support for UART5 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART5) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART5 FALSE
+#endif
+
+/**
+ * @brief UART driver on USART6 enable switch.
+ * @details If set to @p TRUE the support for USART6 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_USART6) || defined(__DOXYGEN__)
+#define STM32_UART_USE_USART6 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART7 enable switch.
+ * @details If set to @p TRUE the support for UART7 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART7) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART7 FALSE
+#endif
+
+/**
+ * @brief UART driver on UART8 enable switch.
+ * @details If set to @p TRUE the support for UART8 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_UART_USE_UART8) || defined(__DOXYGEN__)
+#define STM32_UART_USE_UART8 FALSE
+#endif
+
+/**
+ * @brief USART1 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART1_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART2 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART2_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART3 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART3_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART4 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART4_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART5 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART5_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART6 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_USART6_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART6_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART7 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART7_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART7_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief UART8 interrupt priority level setting.
+ */
+#if !defined(STM32_UART_UART8_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART8_IRQ_PRIORITY 12
+#endif
+
+/**
+ * @brief USART1 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART1_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART2 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART2_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART3 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART3_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART3_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART4 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART4_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART4_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART5 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART5_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART5_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief USART6 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_USART6_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_USART6_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART7 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART7_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART7_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART8 DMA priority (0..3|lowest..highest).
+ * @note The priority level is used for both the TX and RX DMA channels but
+ * because of the channels ordering the RX channel has always priority
+ * over the TX channel.
+ */
+#if !defined(STM32_UART_UART8_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_UART_UART8_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief UART 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_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_UART_USE_USART1 && !STM32_HAS_USART1
+#error "USART1 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_USART2 && !STM32_HAS_USART2
+#error "USART2 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_USART3 && !STM32_HAS_USART3
+#error "USART3 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART4 && !STM32_HAS_UART4
+#error "UART4 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART5 && !STM32_HAS_UART5
+#error "UART5 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART7 && !STM32_HAS_UART7
+#error "UART7 not present in the selected device"
+#endif
+
+#if STM32_UART_USE_UART8 && !STM32_HAS_UART8
+#error "UART8 not present in the selected device"
+#endif
+
+#if !STM32_UART_USE_USART1 && !STM32_UART_USE_USART2 && \
+ !STM32_UART_USE_USART3 && !STM32_UART_USE_UART4 && \
+ !STM32_UART_USE_UART5 && !STM32_UART_USE_USART6 && \
+ !STM32_UART_USE_UART7 && !STM32_UART_USE_UART8
+#error "UART driver activated but no USART/UART peripheral assigned"
+#endif
+
+#if !defined(STM32_USART1_SUPPRESS_ISR) && \
+ STM32_UART_USE_USART1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART1"
+#endif
+
+#if !defined(STM32_USART2_SUPPRESS_ISR) && \
+ STM32_UART_USE_USART2 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART2"
+#endif
+
+#if !defined(STM32_USART3_SUPPRESS_ISR) && \
+ STM32_UART_USE_USART3 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART3_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART3"
+#endif
+
+#if !defined(STM32_UART4_SUPPRESS_ISR) && \
+ STM32_UART_USE_UART4 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART4_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART4"
+#endif
+
+#if !defined(STM32_UART5_SUPPRESS_ISR) && \
+ STM32_UART_USE_UART5 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART5_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART5"
+#endif
+
+#if !defined(STM32_USART6_SUPPRESS_ISR) && \
+ STM32_UART_USE_USART6 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_USART6_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USART6"
+#endif
+
+#if !defined(STM32_UART7_SUPPRESS_ISR) && \
+ STM32_UART_USE_UART7 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART7_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART7"
+#endif
+
+#if !defined(STM32_UART8_SUPPRESS_ISR) && \
+ STM32_UART_USE_UART8 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_UART_UART8_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to UART8"
+#endif
+
+/* Check on DMA priorities.*/
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART1"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART2"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART3_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART3"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART4_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART4"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART5_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART5"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART6_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to USART6"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART7_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART7"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART8_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to UART8"
+#endif
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_UART_USE_USART1 && (!defined(STM32_UART_USART1_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART1_TX_DMA_STREAM))
+#error "USART1 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_USART2 && (!defined(STM32_UART_USART2_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART2_TX_DMA_STREAM))
+#error "USART2 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_USART3 && (!defined(STM32_UART_USART3_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART3_TX_DMA_STREAM))
+#error "USART3 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART4 && (!defined(STM32_UART_UART4_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART4_TX_DMA_STREAM))
+#error "UART4 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART5 && (!defined(STM32_UART_UART5_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART5_TX_DMA_STREAM))
+#error "UART5 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_USART6 && (!defined(STM32_UART_USART6_RX_DMA_STREAM) || \
+ !defined(STM32_UART_USART6_TX_DMA_STREAM))
+#error "USART6 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART7 && (!defined(STM32_UART_UART7_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART7_TX_DMA_STREAM))
+#error "UART7 DMA streams not defined"
+#endif
+
+#if STM32_UART_USE_UART8 && (!defined(STM32_UART_UART8_RX_DMA_STREAM) || \
+ !defined(STM32_UART_UART8_TX_DMA_STREAM))
+#error "UART8 DMA streams not defined"
+#endif
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART1_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART1 RX"
+#endif
+
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART1_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART1 TX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART2_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART2 RX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART2_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART2 TX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART3_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART3 RX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART3_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART3 TX"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART4_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART4 RX"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART4_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART4 TX"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART5_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART5 RX"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART5_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART5 TX"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART6_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART6 RX"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_USART6_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to USART6 TX"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART7_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART7 RX"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART7_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART7 TX"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART8_RX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART8 RX"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_STREAM(STM32_UART_UART8_TX_DMA_STREAM)
+#error "Invalid DMA channel assigned to UART8 TX"
+#endif
+
+/* Devices without DMAMUX require an additional check.*/
+#if STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX
+
+/* Check on the validity of the assigned DMA channels.*/
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_RX_DMA_STREAM, \
+ STM32_USART1_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART1 RX"
+#endif
+
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_TX_DMA_STREAM, \
+ STM32_USART1_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART1 TX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_RX_DMA_STREAM, \
+ STM32_USART2_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART2 RX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_TX_DMA_STREAM, \
+ STM32_USART2_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART2 TX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_RX_DMA_STREAM, \
+ STM32_USART3_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART3 RX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_TX_DMA_STREAM, \
+ STM32_USART3_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART3 TX"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_RX_DMA_STREAM, \
+ STM32_UART4_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART4 RX"
+#endif
+
+#if STM32_UART_USE_UART4 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_TX_DMA_STREAM, \
+ STM32_UART4_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART4 TX"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_RX_DMA_STREAM, \
+ STM32_UART5_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART5 RX"
+#endif
+
+#if STM32_UART_USE_UART5 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_TX_DMA_STREAM, \
+ STM32_UART5_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART5 TX"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_RX_DMA_STREAM, \
+ STM32_USART6_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART6 RX"
+#endif
+
+#if STM32_UART_USE_USART6 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_TX_DMA_STREAM, \
+ STM32_USART6_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART6 TX"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_RX_DMA_STREAM, \
+ STM32_UART7_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART7 RX"
+#endif
+
+#if STM32_UART_USE_UART7 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART7_TX_DMA_STREAM, \
+ STM32_UART7_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART7 TX"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_RX_DMA_STREAM, \
+ STM32_UART8_RX_DMA_MSK)
+#error "invalid DMA stream associated to UART8 RX"
+#endif
+
+#if STM32_UART_USE_UART8 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_UART8_TX_DMA_STREAM, \
+ STM32_UART8_TX_DMA_MSK)
+#error "invalid DMA stream associated to UART8 TX"
+#endif
+
+#endif /* STM32_ADVANCED_DMA && !STM32_DMA_SUPPORTS_DMAMUX */
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief UART driver condition flags type.
+ */
+typedef uint32_t uartflags_t;
+
+/**
+ * @brief Structure representing an UART driver.
+ */
+typedef struct UARTDriver UARTDriver;
+
+/**
+ * @brief Generic UART notification callback type.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ */
+typedef void (*uartcb_t)(UARTDriver *uartp);
+
+/**
+ * @brief Character received UART notification callback type.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] c received character
+ */
+typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c);
+
+/**
+ * @brief Receive error UART notification callback type.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] e receive error mask
+ */
+typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e);
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief End of transmission buffer callback.
+ */
+ uartcb_t txend1_cb;
+ /**
+ * @brief Physical end of transmission callback.
+ */
+ uartcb_t txend2_cb;
+ /**
+ * @brief Receive buffer filled callback.
+ */
+ uartcb_t rxend_cb;
+ /**
+ * @brief Character received while out if the @p UART_RECEIVE state.
+ */
+ uartccb_t rxchar_cb;
+ /**
+ * @brief Receive error callback.
+ */
+ uartecb_t rxerr_cb;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Receiver timeout callback.
+ * @details Handles both idle and timeout interrupts depending on configured
+ * flags in CR registers and supported hardware features.
+ */
+ uartcb_t timeout_cb;
+ /**
+ * @brief Receiver timeout value in terms of number of bit duration.
+ * @details Set it to 0 when you want to handle idle interrupt instead of
+ * hardware timeout.
+ */
+ uint32_t timeout;
+ /**
+ * @brief Bit rate.
+ */
+ uint32_t speed;
+ /**
+ * @brief Initialization value for the CR1 register.
+ */
+ uint32_t cr1;
+ /**
+ * @brief Initialization value for the CR2 register.
+ */
+ uint32_t cr2;
+ /**
+ * @brief Initialization value for the CR3 register.
+ */
+ uint32_t cr3;
+} UARTConfig;
+
+/**
+ * @brief Structure representing an UART driver.
+ */
+struct UARTDriver {
+ /**
+ * @brief Driver state.
+ */
+ uartstate_t state;
+ /**
+ * @brief Transmitter state.
+ */
+ uarttxstate_t txstate;
+ /**
+ * @brief Receiver state.
+ */
+ uartrxstate_t rxstate;
+ /**
+ * @brief Current configuration data.
+ */
+ const UARTConfig *config;
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
+#if defined(UART_DRIVER_EXT_FIELDS)
+ UART_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the USART registers block.
+ */
+ USART_TypeDef *usart;
+ /**
+ * @brief Clock frequency for the associated USART/UART.
+ */
+ uint32_t clock;
+ /**
+ * @brief Receive DMA mode bit mask.
+ */
+ uint32_t dmarxmode;
+ /**
+ * @brief Send DMA mode bit mask.
+ */
+ uint32_t dmatxmode;
+ /**
+ * @brief Receive DMA channel.
+ */
+ const stm32_dma_stream_t *dmarx;
+ /**
+ * @brief Transmit DMA channel.
+ */
+ const stm32_dma_stream_t *dmatx;
+ /**
+ * @brief Default receive buffer while into @p UART_RX_IDLE state.
+ */
+ volatile uint16_t rxbuf;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_UART_USE_USART1 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD1;
+#endif
+
+#if STM32_UART_USE_USART2 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD2;
+#endif
+
+#if STM32_UART_USE_USART3 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD3;
+#endif
+
+#if STM32_UART_USE_UART4 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD4;
+#endif
+
+#if STM32_UART_USE_UART5 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD5;
+#endif
+
+#if STM32_UART_USE_USART6 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD6;
+#endif
+
+#if STM32_UART_USE_UART7 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD7;
+#endif
+
+#if STM32_UART_USE_UART8 && !defined(__DOXYGEN__)
+extern UARTDriver UARTD8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void uart_lld_init(void);
+ void uart_lld_start(UARTDriver *uartp);
+ void uart_lld_stop(UARTDriver *uartp);
+ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf);
+ size_t uart_lld_stop_send(UARTDriver *uartp);
+ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf);
+ size_t uart_lld_stop_receive(UARTDriver *uartp);
+ void uart_lld_serve_interrupt(UARTDriver *uartp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_UART */
+
+#endif /* HAL_UART_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc new file mode 100644 index 0000000..223ce2e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_lpuart1.inc @@ -0,0 +1,110 @@ +/* + 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 USARTv2/stm32_lpuart1.inc + * @brief Shared LPUART1 handler. + * + * @addtogroup STM32_LPUART1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_LPUART1) +#error "STM32_HAS_LPUART1 not defined in registry" +#endif + +#if STM32_HAS_LPUART1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_LPUART1_PRIORITY) +#error "STM32_IRQ_LPUART1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_LPUART1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_LPUART1_PRIORITY" +#endif + +#endif /* STM32_HAS_LPUART1 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_LPUART1) +#define STM32_LPUART1_IS_USED TRUE +#else +#define STM32_LPUART1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void lpuart1_irq_init(void) { +#if STM32_LPUART1_IS_USED + nvicEnableVector(STM32_LPUART1_NUMBER, STM32_IRQ_LPUART1_PRIORITY); +#endif +} + +static inline void lpuart1_irq_deinit(void) { +#if STM32_LPUART1_IS_USED + nvicDisableVector(STM32_LPUART1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_LPUART1_IS_USED || defined(__DOXYGEN__) +/** + * @brief LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LPUART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_LPUART1 + sd_lld_serve_interrupt(&LPSD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc new file mode 100644 index 0000000..5dd7b51 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart4.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_uart4.inc + * @brief Shared UART4 handler. + * + * @addtogroup STM32_UART4_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART4) +#error "STM32_HAS_UART4 not defined in registry" +#endif + +#if STM32_HAS_UART4 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART4_PRIORITY) +#error "STM32_IRQ_UART4_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART4_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART4_PRIORITY" +#endif + +#endif /* STM32_HAS_UART4 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) && \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#error "UART4 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) || \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#define STM32_UART4_IS_USED TRUE +#else +#define STM32_UART4_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart4_irq_init(void) { +#if STM32_UART4_IS_USED + nvicEnableVector(STM32_UART4_NUMBER, STM32_IRQ_UART4_PRIORITY); +#endif +} + +static inline void uart4_irq_deinit(void) { +#if STM32_UART4_IS_USED + nvicDisableVector(STM32_UART4_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART4_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART4 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART4_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART4 + sd_lld_serve_interrupt(&SD4); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART4 + uart_lld_serve_interrupt(&UARTD4); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc new file mode 100644 index 0000000..b382d84 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart5.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_uart5.inc + * @brief Shared UART5 handler. + * + * @addtogroup STM32_UART5_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART5) +#error "STM32_HAS_UART5 not defined in registry" +#endif + +#if STM32_HAS_UART5 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART5_PRIORITY) +#error "STM32_IRQ_UART5_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART5_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART5_PRIORITY" +#endif + +#endif /* STM32_HAS_UART5 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) && \ + (HAL_USE_UART && STM32_UART_USE_UART5) +#error "UART5 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) || \ + (HAL_USE_UART && STM32_UART_USE_UART5) +#define STM32_UART5_IS_USED TRUE +#else +#define STM32_UART5_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart5_irq_init(void) { +#if STM32_UART5_IS_USED + nvicEnableVector(STM32_UART5_NUMBER, STM32_IRQ_UART5_PRIORITY); +#endif +} + +static inline void uart5_irq_deinit(void) { +#if STM32_UART5_IS_USED + nvicDisableVector(STM32_UART5_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART5_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART5 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART5 + sd_lld_serve_interrupt(&SD5); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART5 + uart_lld_serve_interrupt(&UARTD5); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc new file mode 100644 index 0000000..2ec791e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart7.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_uart7.inc + * @brief Shared UART7 handler. + * + * @addtogroup STM32_UART7_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART7) +#error "STM32_HAS_UART7 not defined in registry" +#endif + +#if STM32_HAS_UART7 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART7_PRIORITY) +#error "STM32_IRQ_UART7_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART7_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART7_PRIORITY" +#endif + +#endif /* STM32_HAS_UART7 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART7) && \ + (HAL_USE_UART && STM32_UART_USE_UART7) +#error "UART7 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART7) || \ + (HAL_USE_UART && STM32_UART_USE_UART7) +#define STM32_UART7_IS_USED TRUE +#else +#define STM32_UART7_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart7_irq_init(void) { +#if STM32_UART7_IS_USED + nvicEnableVector(STM32_UART7_NUMBER, STM32_IRQ_UART7_PRIORITY); +#endif +} + +static inline void uart7_irq_deinit(void) { +#if STM32_UART7_IS_USED + nvicDisableVector(STM32_UART7_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART7_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART7 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART7_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART7 + sd_lld_serve_interrupt(&SD7); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART7 + uart_lld_serve_interrupt(&UARTD7); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc new file mode 100644 index 0000000..8958431 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_uart8.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_uart8.inc + * @brief Shared UART8 handler. + * + * @addtogroup STM32_UART8_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART8) +#error "STM32_HAS_UART8 not defined in registry" +#endif + +#if STM32_HAS_UART8 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_UART8_PRIORITY) +#error "STM32_IRQ_UART8_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_UART8_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_UART8_PRIORITY" +#endif + +#endif /* STM32_HAS_UART8 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART8) && \ + (HAL_USE_UART && STM32_UART_USE_UART8) +#error "UART8 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART8) || \ + (HAL_USE_UART && STM32_UART_USE_UART8) +#define STM32_UART8_IS_USED TRUE +#else +#define STM32_UART8_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void uart8_irq_init(void) { +#if STM32_UART8_IS_USED + nvicEnableVector(STM32_UART8_NUMBER, STM32_IRQ_UART8_PRIORITY); +#endif +} + +static inline void uart8_irq_deinit(void) { +#if STM32_UART8_IS_USED + nvicDisableVector(STM32_UART8_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_UART8_IS_USED || defined(__DOXYGEN__) +/** + * @brief UART8 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_UART8_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART8 + sd_lld_serve_interrupt(&SD8); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART8 + uart_lld_serve_interrupt(&UARTD8); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc new file mode 100644 index 0000000..19aac10 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart1.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_usart1.inc + * @brief Shared USART1 handler. + * + * @addtogroup STM32_USART1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART1) +#error "STM32_HAS_USART1 not defined in registry" +#endif + +#if STM32_HAS_USART1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART1_PRIORITY) +#error "STM32_IRQ_USART1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART1_PRIORITY" +#endif + +#endif /* STM32_HAS_USART1 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART1) && \ + (HAL_USE_UART && STM32_UART_USE_USART1) +#error "USART1 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART1) || \ + (HAL_USE_UART && STM32_UART_USE_USART1) +#define STM32_USART1_IS_USED TRUE +#else +#define STM32_USART1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart1_irq_init(void) { +#if STM32_USART1_IS_USED + nvicEnableVector(STM32_USART1_NUMBER, STM32_IRQ_USART1_PRIORITY); +#endif +} + +static inline void usart1_irq_deinit(void) { +#if STM32_USART1_IS_USED + nvicDisableVector(STM32_USART1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART1_IS_USED|| defined(__DOXYGEN__) +/** + * @brief USART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART1 + sd_lld_serve_interrupt(&SD1); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART1 + uart_lld_serve_interrupt(&UARTD1); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc new file mode 100644 index 0000000..c4b9000 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart2.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_usart2.inc + * @brief Shared USART2 handler. + * + * @addtogroup STM32_USART2_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART2) +#error "STM32_HAS_USART2 not defined in registry" +#endif + +#if STM32_HAS_USART2 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART2_PRIORITY) +#error "STM32_IRQ_USART2_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART2_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART2_PRIORITY" +#endif + +#endif /* STM32_HAS_USART2 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART2) && \ + (HAL_USE_UART && STM32_UART_USE_USART2) +#error "USART2 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART2) || \ + (HAL_USE_UART && STM32_UART_USE_USART2) +#define STM32_USART2_IS_USED TRUE +#else +#define STM32_USART2_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart2_irq_init(void) { +#if STM32_USART2_IS_USED + nvicEnableVector(STM32_USART2_NUMBER, STM32_IRQ_USART2_PRIORITY); +#endif +} + +static inline void usart2_irq_deinit(void) { +#if STM32_USART2_IS_USED + nvicDisableVector(STM32_USART2_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART2_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART2_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART2 + sd_lld_serve_interrupt(&SD2); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART2 + uart_lld_serve_interrupt(&UARTD2); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc new file mode 100644 index 0000000..ff5dbda --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_usart3.inc + * @brief Shared USART3 handler. + * + * @addtogroup STM32_USART3_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART3) +#error "STM32_HAS_USART3 not defined in registry" +#endif + +#if STM32_HAS_USART3 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART3_PRIORITY) +#error "STM32_IRQ_USART3_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART3_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART3_PRIORITY" +#endif + +#endif /* STM32_HAS_USART3 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) && \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#error "USART3 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) || \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#define STM32_USART3_IS_USED TRUE +#else +#define STM32_USART3_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart3_irq_init(void) { +#if STM32_USART3_IS_USED + nvicEnableVector(STM32_USART3_NUMBER, STM32_IRQ_USART3_PRIORITY); +#endif +} + +static inline void usart3_irq_deinit(void) { +#if STM32_USART3_IS_USED + nvicDisableVector(STM32_USART3_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART3_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART3 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART3 + sd_lld_serve_interrupt(&SD3); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART3 + uart_lld_serve_interrupt(&UARTD3); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc new file mode 100644 index 0000000..596237f --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart3_4_lp1.inc @@ -0,0 +1,157 @@ +/* + 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 USARTv2/stm32_usart3_4_lp1.inc + * @brief Shared USART3, USART4, LPUART1 handler. + * + * @addtogroup STM32_USART3_4_LP1_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART3) +#error "STM32_HAS_USART3 not defined in registry" +#endif + +#if !defined(STM32_HAS_UART4) +#error "STM32_HAS_UART4 not defined in registry" +#endif + +#if !defined(STM32_HAS_LPUART1) +#error "STM32_HAS_LPUART1 not defined in registry" +#endif + +#if STM32_HAS_USART3 || STM32_HAS_UART4 || STM32_HAS_LPUART1 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART3_4_LP1_PRIORITY) +#error "STM32_IRQ_USART3_4_LP1_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART3_4_LP1_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART3_4_LP1_PRIORITY" +#endif + +#endif /* STM32_HAS_USART3 || STM32_HAS_UART4 || STM32_HAS_LPUART1 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) && \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#error "USART3 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) && \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#error "USART4 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART3) || \ + (HAL_USE_UART && STM32_UART_USE_USART3) +#define STM32_USART3_IS_USED TRUE +#else +#define STM32_USART3_IS_USED FALSE +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) || \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#define STM32_USART4_IS_USED TRUE +#else +#define STM32_USART4_IS_USED FALSE +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_LPUART1) +#define STM32_LPUART1_IS_USED TRUE +#else +#define STM32_LPUART1_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart3_usart4_lpuart1_irq_init(void) { +#if STM32_USART3_IS_USED || STM32_USART4_IS_USED || STM32_LPUART1_IS_USED + nvicEnableVector(STM32_USART3_4_LP1_NUMBER, STM32_IRQ_USART3_4_LP1_PRIORITY); +#endif +} + +static inline void usart3_usart4_lpuart1_irq_deinit(void) { +#if STM32_USART3_IS_USED || STM32_USART4_IS_USED || STM32_LPUART1_IS_USED + nvicDisableVector(STM32_USART3_4_LP1_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART3_IS_USED || STM32_USART4_IS_USED || \ + STM32_LPUART1_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART4, USART5, LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART3_4_LP1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART3 + sd_lld_serve_interrupt(&SD3); +#endif +#if STM32_SERIAL_USE_UART4 + sd_lld_serve_interrupt(&SD4); +#endif +#if STM32_SERIAL_USE_LPUART1 + sd_lld_serve_interrupt(&LPSD1); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART3 + uart_lld_serve_interrupt(&UARTD3); +#endif +#if STM32_UART_USE_UART4 + uart_lld_serve_interrupt(&UARTD4); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc new file mode 100644 index 0000000..7d003a3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart4_5.inc @@ -0,0 +1,144 @@ +/* + 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 USARTv2/stm32_usart4_5.inc + * @brief Shared USART4, USART5 handler. + * + * @addtogroup STM32_USART4_5_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_UART4) +#error "STM32_HAS_UART4 not defined in registry" +#endif + +#if !defined(STM32_HAS_UART5) +#error "STM32_HAS_UART5 not defined in registry" +#endif + +#if STM32_HAS_UART4 || STM32_HAS_UART5 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART4_5_PRIORITY) +#error "STM32_IRQ_USART4_5_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART4_5_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART4_5_PRIORITY" +#endif + +#endif /* STM32_HAS_UART4 || STM32_HAS_UART5 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) && \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#error "USART4 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) && \ + (HAL_USE_UART && STM32_UART_USE_UART5) +#error "USART5 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART4) || \ + (HAL_USE_UART && STM32_UART_USE_UART4) +#define STM32_USART4_IS_USED TRUE +#else +#define STM32_USART4_IS_USED FALSE +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_UART5) || \ + (HAL_USE_UART && STM32_UART_USE_UART45) +#define STM32_USART5_IS_USED TRUE +#else +#define STM32_USART5_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart4_usart5_irq_init(void) { +#if STM32_USART4_IS_USED || STM32_USART5_IS_USED + nvicEnableVector(STM32_USART4_5_NUMBER, STM32_IRQ_USART4_5_PRIORITY); +#endif +} + +static inline void usart4_usart5_irq_deinit(void) { +#if STM32_USART4_IS_USED || STM32_USART5_IS_USED + nvicDisableVector(STM32_USART4_5_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART4_IS_USED || STM32_USART5_IS_USED || \ + defined(__DOXYGEN__) +/** + * @brief USART4, USART5, LPUART1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART4_5_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_UART4 + sd_lld_serve_interrupt(&SD4); +#endif +#if STM32_SERIAL_USE_UART5 + sd_lld_serve_interrupt(&SD5); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_UART4 + uart_lld_serve_interrupt(&UARTD4); +#endif +#if STM32_UART_USE_UART5 + uart_lld_serve_interrupt(&UARTD5); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc new file mode 100644 index 0000000..ea812a8 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USARTv2/stm32_usart6.inc @@ -0,0 +1,121 @@ +/* + 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 USARTv2/stm32_usart6.inc + * @brief Shared USART6 handler. + * + * @addtogroup STM32_USART6_HANDLER + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* Registry checks for robustness.*/ +#if !defined(STM32_HAS_USART6) +#error "STM32_HAS_USART6 not defined in registry" +#endif + +#if STM32_HAS_USART6 + +/* Priority settings checks.*/ +#if !defined(STM32_IRQ_USART6_PRIORITY) +#error "STM32_IRQ_USART6_PRIORITY not defined in mcuconf.h" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_IRQ_USART6_PRIORITY) +#error "Invalid IRQ priority assigned to STM32_IRQ_USART6_PRIORITY" +#endif + +#endif /* STM32_HAS_USART6 */ + +/* Other checks.*/ +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART6) && \ + (HAL_USE_UART && STM32_UART_USE_USART6) +#error "USART6 used by multiple drivers" +#endif + +#if (HAL_USE_SERIAL && STM32_SERIAL_USE_USART6) || \ + (HAL_USE_UART && STM32_UART_USE_USART6) +#define STM32_USART6_IS_USED TRUE +#else +#define STM32_USART6_IS_USED FALSE +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void usart6_irq_init(void) { +#if STM32_USART6_IS_USED + nvicEnableVector(STM32_USART6_NUMBER, STM32_IRQ_USART6_PRIORITY); +#endif +} + +static inline void usart6_irq_deinit(void) { +#if STM32_USART6_IS_USED + nvicDisableVector(STM32_USART6_NUMBER); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USART6_IS_USED || defined(__DOXYGEN__) +/** + * @brief USART6 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_USART6_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + +#if HAL_USE_SERIAL +#if STM32_SERIAL_USE_USART6 + sd_lld_serve_interrupt(&SD6); +#endif +#endif +#if HAL_USE_UART +#if STM32_UART_USE_USART6 + uart_lld_serve_interrupt(&UARTD6); +#endif +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk new file mode 100644 index 0000000..1a6d862 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c new file mode 100644 index 0000000..20607b7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.c @@ -0,0 +1,874 @@ +/*
+ 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 USBv1/hal_usb_lld.c
+ * @brief STM32 USB subsystem low level driver source.
+ *
+ * @addtogroup USB
+ * @{
+ */
+
+#include <string.h>
+
+#include "hal.h"
+
+#if HAL_USE_USB || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define BTABLE_ADDR 0x0000
+
+#define EPR_EP_TYPE_IS_ISO(bits) ((bits & EPR_EP_TYPE_MASK) == EPR_EP_TYPE_ISO)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief USB1 driver identifier.*/
+#if STM32_USB_USE_USB1 || defined(__DOXYGEN__)
+USBDriver USBD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief EP0 state.
+ * @note It is an union because IN and OUT endpoints are never used at the
+ * same time for EP0.
+ */
+static union {
+ /**
+ * @brief IN EP0 state.
+ */
+ USBInEndpointState in;
+ /**
+ * @brief OUT EP0 state.
+ */
+ USBOutEndpointState out;
+} ep0_state;
+
+/**
+ * @brief Buffer for the EP0 setup packets.
+ */
+static uint8_t ep0setup_buffer[8];
+
+/**
+ * @brief EP0 initialization structure.
+ */
+static const USBEndpointConfig ep0config = {
+ USB_EP_MODE_TYPE_CTRL,
+ _usb_ep0setup,
+ _usb_ep0in,
+ _usb_ep0out,
+ 0x40,
+ 0x40,
+ &ep0_state.in,
+ &ep0_state.out,
+ 1,
+ ep0setup_buffer
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Resets the packet memory allocator.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ */
+static void usb_pm_reset(USBDriver *usbp) {
+
+ /* The first 64 bytes are reserved for the descriptors table. The effective
+ available RAM for endpoint buffers is just 448 bytes.*/
+ usbp->pmnext = 64;
+}
+
+/**
+ * @brief Resets the packet memory allocator.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] size size of the packet buffer to allocate
+ * @return The packet buffer address.
+ */
+static uint32_t usb_pm_alloc(USBDriver *usbp, size_t size) {
+ uint32_t next;
+
+ next = usbp->pmnext;
+ usbp->pmnext += (size + 1) & ~1;
+ osalDbgAssert(usbp->pmnext <= STM32_USB_PMA_SIZE, "PMA overflow");
+ return next;
+}
+
+/**
+ * @brief Reads from a dedicated packet buffer.
+ *
+ * @param[in] ep endpoint number
+ * @param[out] buf buffer where to copy the packet data
+ * @return The size of the receivee packet.
+ *
+ * @notapi
+ */
+static size_t usb_packet_read_to_buffer(usbep_t ep, uint8_t *buf) {
+ size_t i, n;
+ stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep);
+ stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->RXADDR0);
+#if STM32_USB_USE_ISOCHRONOUS
+ uint32_t epr = STM32_USB->EPR[ep];
+
+ /* Double buffering is always enabled for isochronous endpoints, and
+ although we overlap the two buffers for simplicity, we still need
+ to read from the right counter. The DTOG_RX bit indicates the buffer
+ that is currently in use by the USB peripheral, that is, the buffer
+ in which the next received packet will be stored, so we need to
+ read the counter of the OTHER buffer, which is where the last
+ received packet was stored.*/
+ if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_RX))
+ n = (size_t)udp->RXCOUNT1 & RXCOUNT_COUNT_MASK;
+ else
+ n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK;
+#else
+ n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK;
+#endif
+
+ i = n;
+
+#if STM32_USB_USE_FAST_COPY
+ while (i >= 16) {
+ uint32_t w;
+
+ w = *(pmap + 0);
+ *(buf + 0) = (uint8_t)w;
+ *(buf + 1) = (uint8_t)(w >> 8);
+ w = *(pmap + 1);
+ *(buf + 2) = (uint8_t)w;
+ *(buf + 3) = (uint8_t)(w >> 8);
+ w = *(pmap + 2);
+ *(buf + 4) = (uint8_t)w;
+ *(buf + 5) = (uint8_t)(w >> 8);
+ w = *(pmap + 3);
+ *(buf + 6) = (uint8_t)w;
+ *(buf + 7) = (uint8_t)(w >> 8);
+ w = *(pmap + 4);
+ *(buf + 8) = (uint8_t)w;
+ *(buf + 9) = (uint8_t)(w >> 8);
+ w = *(pmap + 5);
+ *(buf + 10) = (uint8_t)w;
+ *(buf + 11) = (uint8_t)(w >> 8);
+ w = *(pmap + 6);
+ *(buf + 12) = (uint8_t)w;
+ *(buf + 13) = (uint8_t)(w >> 8);
+ w = *(pmap + 7);
+ *(buf + 14) = (uint8_t)w;
+ *(buf + 15) = (uint8_t)(w >> 8);
+
+ i -= 16;
+ buf += 16;
+ pmap += 8;
+ }
+#endif /* STM32_USB_USE_FAST_COPY */
+
+ while (i >= 2) {
+ uint32_t w = *pmap++;
+ *buf++ = (uint8_t)w;
+ *buf++ = (uint8_t)(w >> 8);
+ i -= 2;
+ }
+
+ if (i >= 1) {
+ *buf = (uint8_t)*pmap;
+ }
+
+ return n;
+}
+
+/**
+ * @brief Writes to a dedicated packet buffer.
+ *
+ * @param[in] ep endpoint number
+ * @param[in] buf buffer where to fetch the packet data
+ * @param[in] n maximum number of bytes to copy. This value must
+ * not exceed the maximum packet size for this endpoint.
+ *
+ * @notapi
+ */
+static void usb_packet_write_from_buffer(usbep_t ep,
+ const uint8_t *buf,
+ size_t n) {
+ stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep);
+ stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->TXADDR0);
+ int i = (int)n;
+
+#if STM32_USB_USE_ISOCHRONOUS
+ uint32_t epr = STM32_USB->EPR[ep];
+
+ /* Double buffering is always enabled for isochronous endpoints, and
+ although we overlap the two buffers for simplicity, we still need
+ to write to the right counter. The DTOG_TX bit indicates the buffer
+ that is currently in use by the USB peripheral, that is, the buffer
+ from which the next packet will be sent, so we need to write the
+ counter of that buffer.*/
+ if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX))
+ udp->TXCOUNT1 = (stm32_usb_pma_t)n;
+ else
+ udp->TXCOUNT0 = (stm32_usb_pma_t)n;
+#else
+ udp->TXCOUNT0 = (stm32_usb_pma_t)n;
+#endif
+
+#if STM32_USB_USE_FAST_COPY
+ while (i >= 16) {
+ uint32_t w;
+
+ w = *(buf + 0);
+ w |= *(buf + 1) << 8;
+ *(pmap + 0) = (stm32_usb_pma_t)w;
+ w = *(buf + 2);
+ w |= *(buf + 3) << 8;
+ *(pmap + 1) = (stm32_usb_pma_t)w;
+ w = *(buf + 4);
+ w |= *(buf + 5) << 8;
+ *(pmap + 2) = (stm32_usb_pma_t)w;
+ w = *(buf + 6);
+ w |= *(buf + 7) << 8;
+ *(pmap + 3) = (stm32_usb_pma_t)w;
+ w = *(buf + 8);
+ w |= *(buf + 9) << 8;
+ *(pmap + 4) = (stm32_usb_pma_t)w;
+ w = *(buf + 10);
+ w |= *(buf + 11) << 8;
+ *(pmap + 5) = (stm32_usb_pma_t)w;
+ w = *(buf + 12);
+ w |= *(buf + 13) << 8;
+ *(pmap + 6) = (stm32_usb_pma_t)w;
+ w = *(buf + 14);
+ w |= *(buf + 15) << 8;
+ *(pmap + 7) = (stm32_usb_pma_t)w;
+
+ i -= 16;
+ buf += 16;
+ pmap += 8;
+ }
+#endif /* STM32_USB_USE_FAST_COPY */
+
+ while (i > 0) {
+ uint32_t w;
+
+ w = *buf++;
+ w |= *buf++ << 8;
+ *pmap++ = (stm32_usb_pma_t)w;
+ i -= 2;
+ }
+}
+
+/**
+ * @brief Common ISR code, serves the EP-related interrupts.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+static void usb_serve_endpoints(USBDriver *usbp, uint32_t ep) {
+ size_t n;
+ uint32_t epr = STM32_USB->EPR[ep];
+ const USBEndpointConfig *epcp = usbp->epc[ep];
+
+ if (epr & EPR_CTR_TX) {
+ /* IN endpoint, transmission.*/
+ USBInEndpointState *isp = epcp->in_state;
+
+ EPR_CLEAR_CTR_TX(ep);
+
+ isp->txcnt += isp->txlast;
+ n = isp->txsize - isp->txcnt;
+ if (n > 0) {
+ /* Transfer not completed, there are more packets to send.*/
+ if (n > epcp->in_maxsize)
+ n = epcp->in_maxsize;
+
+ /* Writes the packet from the defined buffer.*/
+ isp->txbuf += isp->txlast;
+ isp->txlast = n;
+ usb_packet_write_from_buffer(ep, isp->txbuf, n);
+
+ /* Starting IN operation.*/
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
+ }
+ else {
+ /* Transfer completed, invokes the callback.*/
+ _usb_isr_invoke_in_cb(usbp, ep);
+ }
+ }
+ if (epr & EPR_CTR_RX) {
+ /* OUT endpoint, receive.*/
+
+ EPR_CLEAR_CTR_RX(ep);
+
+ if (epr & EPR_SETUP) {
+ /* Setup packets handling, setup packets are handled using a
+ specific callback.*/
+ _usb_isr_invoke_setup_cb(usbp, ep);
+ }
+ else {
+ USBOutEndpointState *osp = epcp->out_state;
+
+ /* Reads the packet into the defined buffer.*/
+ n = usb_packet_read_to_buffer(ep, osp->rxbuf);
+ osp->rxbuf += n;
+
+ /* Transaction data updated.*/
+ osp->rxcnt += n;
+ osp->rxsize -= n;
+ osp->rxpkts -= 1;
+
+ /* The transaction is completed if the specified number of packets
+ has been received or the current packet is a short packet.*/
+ if ((n < epcp->out_maxsize) || (osp->rxpkts == 0)) {
+ /* Transfer complete, invokes the callback.*/
+ _usb_isr_invoke_out_cb(usbp, ep);
+ }
+ else {
+ /* Transfer not complete, there are more packets to receive.*/
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
+ }
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_USB_USE_USB1 || defined(__DOXYGEN__)
+#if STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER
+#if STM32_USB_USE_ISOCHRONOUS
+/**
+ * @brief USB high priority interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USB1_HP_HANDLER) {
+ uint32_t istr;
+ USBDriver *usbp = &USBD1;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Endpoint events handling.*/
+ istr = STM32_USB->ISTR;
+ while (istr & ISTR_CTR) {
+ usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK);
+ istr = STM32_USB->ISTR;
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_USB_USE_ISOCHRONOUS */
+#endif /* STM32_USB1_LP_NUMBER != STM32_USB1_HP_NUMBER */
+
+/**
+ * @brief USB low priority interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
+ uint32_t istr;
+ USBDriver *usbp = &USBD1;
+
+ OSAL_IRQ_PROLOGUE();
+
+ istr = STM32_USB->ISTR;
+
+ /* USB bus reset condition handling.*/
+ if (istr & ISTR_RESET) {
+ STM32_USB->ISTR = ~ISTR_RESET;
+
+ _usb_reset(usbp);
+ }
+
+ /* USB bus SUSPEND condition handling.*/
+ if (istr & ISTR_SUSP) {
+ STM32_USB->CNTR |= CNTR_FSUSP;
+#if STM32_USB_LOW_POWER_ON_SUSPEND
+ STM32_USB->CNTR |= CNTR_LP_MODE;
+#endif
+ STM32_USB->ISTR = ~ISTR_SUSP;
+
+ _usb_suspend(usbp);
+ }
+
+ /* USB bus WAKEUP condition handling.*/
+ if (istr & ISTR_WKUP) {
+ uint32_t fnr = STM32_USB->FNR;
+ if (!(fnr & FNR_RXDP)) {
+ STM32_USB->CNTR &= ~CNTR_FSUSP;
+
+ _usb_wakeup(usbp);
+ }
+#if STM32_USB_LOW_POWER_ON_SUSPEND
+ else {
+ /* Just noise, going back in SUSPEND mode, reference manual 22.4.5,
+ table 169.*/
+ STM32_USB->CNTR |= CNTR_LP_MODE;
+ }
+#endif
+ STM32_USB->ISTR = ~ISTR_WKUP;
+ }
+
+ /* SOF handling.*/
+ if (istr & ISTR_SOF) {
+ _usb_isr_invoke_sof_cb(usbp);
+ STM32_USB->ISTR = ~ISTR_SOF;
+ }
+
+ /* Endpoint events handling.*/
+ while (istr & ISTR_CTR) {
+ usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK);
+ istr = STM32_USB->ISTR;
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* STM32_USB_USE_USB1 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level USB driver initialization.
+ *
+ * @notapi
+ */
+void usb_lld_init(void) {
+
+ /* Driver initialization.*/
+ usbObjectInit(&USBD1);
+}
+
+/**
+ * @brief Configures and activates the USB peripheral.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_start(USBDriver *usbp) {
+
+ if (usbp->state == USB_STOP) {
+ /* Clock activation.*/
+#if STM32_USB_USE_USB1
+ if (&USBD1 == usbp) {
+ /* USB clock enabled.*/
+ rccEnableUSB(true);
+ /* Powers up the transceiver while holding the USB in reset state.*/
+ STM32_USB->CNTR = CNTR_FRES;
+ /* Enabling the USB IRQ vectors, this also gives enough time to allow
+ the transceiver power up (1uS).*/
+#if STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER
+ nvicEnableVector(STM32_USB1_HP_NUMBER, STM32_USB_USB1_HP_IRQ_PRIORITY);
+#endif
+ nvicEnableVector(STM32_USB1_LP_NUMBER, STM32_USB_USB1_LP_IRQ_PRIORITY);
+ /* Releases the USB reset.*/
+ STM32_USB->CNTR = 0;
+ }
+#endif
+ /* Reset procedure enforced on driver start.*/
+ usb_lld_reset(usbp);
+ }
+}
+
+/**
+ * @brief Deactivates the USB peripheral.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_stop(USBDriver *usbp) {
+
+ /* If in ready state then disables the USB clock.*/
+ if (usbp->state != USB_STOP) {
+#if STM32_USB_USE_USB1
+ if (&USBD1 == usbp) {
+#if STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER
+ nvicDisableVector(STM32_USB1_HP_NUMBER);
+#endif
+ nvicDisableVector(STM32_USB1_LP_NUMBER);
+ STM32_USB->CNTR = CNTR_PDWN | CNTR_FRES;
+ rccDisableUSB();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief USB low level reset routine.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_reset(USBDriver *usbp) {
+ uint32_t cntr;
+
+ /* Post reset initialization.*/
+ STM32_USB->BTABLE = BTABLE_ADDR;
+ STM32_USB->ISTR = 0;
+ STM32_USB->DADDR = DADDR_EF;
+ cntr = /*CNTR_ESOFM | */ CNTR_RESETM | CNTR_SUSPM |
+ CNTR_WKUPM | /*CNTR_ERRM | CNTR_PMAOVRM |*/ CNTR_CTRM;
+ /* The SOF interrupt is only enabled if a callback is defined for
+ this service because it is an high rate source.*/
+ if (usbp->config->sof_cb != NULL)
+ cntr |= CNTR_SOFM;
+ STM32_USB->CNTR = cntr;
+
+ /* Resets the packet memory allocator.*/
+ usb_pm_reset(usbp);
+
+ /* EP0 initialization.*/
+ usbp->epc[0] = &ep0config;
+ usb_lld_init_endpoint(usbp, 0);
+}
+
+/**
+ * @brief Sets the USB address.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_set_address(USBDriver *usbp) {
+
+ STM32_USB->DADDR = (uint32_t)(usbp->address) | DADDR_EF;
+}
+
+/**
+ * @brief Enables an endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
+ uint16_t epr;
+ stm32_usb_descriptor_t *dp;
+ const USBEndpointConfig *epcp = usbp->epc[ep];
+
+ /* Setting the endpoint type. Note that isochronous endpoints cannot be
+ bidirectional because it uses double buffering and both transmit and
+ receive descriptor fields are used for either direction.*/
+ switch (epcp->ep_mode & USB_EP_MODE_TYPE) {
+ case USB_EP_MODE_TYPE_ISOC:
+#if STM32_USB_USE_ISOCHRONOUS
+ osalDbgAssert((epcp->in_state == NULL) || (epcp->out_state == NULL),
+ "isochronous EP cannot be IN and OUT");
+ epr = EPR_EP_TYPE_ISO;
+ break;
+#else
+ osalDbgAssert(false, "isochronous support disabled");
+#endif
+ /* Falls through.*/
+ case USB_EP_MODE_TYPE_BULK:
+ epr = EPR_EP_TYPE_BULK;
+ break;
+ case USB_EP_MODE_TYPE_INTR:
+ epr = EPR_EP_TYPE_INTERRUPT;
+ break;
+ default:
+ epr = EPR_EP_TYPE_CONTROL;
+ }
+
+ dp = USB_GET_DESCRIPTOR(ep);
+
+ /* IN endpoint handling.*/
+ if (epcp->in_state != NULL) {
+ dp->TXCOUNT0 = 0;
+ dp->TXADDR0 = usb_pm_alloc(usbp, epcp->in_maxsize);
+
+#if STM32_USB_USE_ISOCHRONOUS
+ if (epr == EPR_EP_TYPE_ISO) {
+ epr |= EPR_STAT_TX_VALID;
+ dp->TXCOUNT1 = dp->TXCOUNT0;
+ dp->TXADDR1 = dp->TXADDR0; /* Both buffers overlapped.*/
+ }
+ else {
+ epr |= EPR_STAT_TX_NAK;
+ }
+#else
+ epr |= EPR_STAT_TX_NAK;
+#endif
+ }
+
+ /* OUT endpoint handling.*/
+ if (epcp->out_state != NULL) {
+ uint16_t nblocks;
+
+ /* Endpoint size and address initialization.*/
+ if (epcp->out_maxsize > 62)
+ nblocks = (((((epcp->out_maxsize - 1) | 0x1f) + 1) / 32) << 10) |
+ 0x8000;
+ else
+ nblocks = ((((epcp->out_maxsize - 1) | 1) + 1) / 2) << 10;
+ dp->RXCOUNT0 = nblocks;
+ dp->RXADDR0 = usb_pm_alloc(usbp, epcp->out_maxsize);
+
+#if STM32_USB_USE_ISOCHRONOUS
+ if (epr == EPR_EP_TYPE_ISO) {
+ epr |= EPR_STAT_RX_VALID;
+ dp->RXCOUNT1 = dp->RXCOUNT0;
+ dp->RXADDR1 = dp->RXADDR0; /* Both buffers overlapped.*/
+ }
+ else {
+ epr |= EPR_STAT_RX_NAK;
+ }
+#else
+ epr |= EPR_STAT_RX_NAK;
+#endif
+ }
+
+ /* Resetting the data toggling bits for this endpoint.*/
+ if (STM32_USB->EPR[ep] & EPR_DTOG_RX) {
+ epr |= EPR_DTOG_RX;
+ }
+
+ if (STM32_USB->EPR[ep] & EPR_DTOG_TX) {
+ epr |= EPR_DTOG_TX;
+ }
+
+ /* EPxR register setup.*/
+ EPR_SET(ep, epr | ep);
+ EPR_TOGGLE(ep, epr);
+}
+
+/**
+ * @brief Disables all the active endpoints except the endpoint zero.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ *
+ * @notapi
+ */
+void usb_lld_disable_endpoints(USBDriver *usbp) {
+ unsigned i;
+
+ /* Resets the packet memory allocator.*/
+ usb_pm_reset(usbp);
+
+ /* Disabling all endpoints.*/
+ for (i = 1; i <= USB_ENDOPOINTS_NUMBER; i++) {
+ EPR_TOGGLE(i, 0);
+ EPR_SET(i, 0);
+ }
+}
+
+/**
+ * @brief Returns the status of an OUT endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return The endpoint status.
+ * @retval EP_STATUS_DISABLED The endpoint is not active.
+ * @retval EP_STATUS_STALLED The endpoint is stalled.
+ * @retval EP_STATUS_ACTIVE The endpoint is active.
+ *
+ * @notapi
+ */
+usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+ switch (STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) {
+ case EPR_STAT_RX_DIS:
+ return EP_STATUS_DISABLED;
+ case EPR_STAT_RX_STALL:
+ return EP_STATUS_STALLED;
+ default:
+ return EP_STATUS_ACTIVE;
+ }
+}
+
+/**
+ * @brief Returns the status of an IN endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return The endpoint status.
+ * @retval EP_STATUS_DISABLED The endpoint is not active.
+ * @retval EP_STATUS_STALLED The endpoint is stalled.
+ * @retval EP_STATUS_ACTIVE The endpoint is active.
+ *
+ * @notapi
+ */
+usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+ switch (STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) {
+ case EPR_STAT_TX_DIS:
+ return EP_STATUS_DISABLED;
+ case EPR_STAT_TX_STALL:
+ return EP_STATUS_STALLED;
+ default:
+ return EP_STATUS_ACTIVE;
+ }
+}
+
+/**
+ * @brief Reads a setup packet from the dedicated packet buffer.
+ * @details This function must be invoked in the context of the @p setup_cb
+ * callback in order to read the received setup packet.
+ * @pre In order to use this function the endpoint must have been
+ * initialized as a control endpoint.
+ * @post The endpoint is ready to accept another packet.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @param[out] buf buffer where to copy the packet data
+ *
+ * @notapi
+ */
+void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
+ stm32_usb_pma_t *pmap;
+ stm32_usb_descriptor_t *udp;
+ uint32_t n;
+
+ (void)usbp;
+ udp = USB_GET_DESCRIPTOR(ep);
+ pmap = USB_ADDR2PTR(udp->RXADDR0);
+ for (n = 0; n < 4; n++) {
+ *(uint16_t *)buf = (uint16_t)*pmap++;
+ buf += 2;
+ }
+}
+
+/**
+ * @brief Starts a receive operation on an OUT endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
+ USBOutEndpointState *osp = usbp->epc[ep]->out_state;
+
+ /* Transfer initialization.*/
+ if (osp->rxsize == 0) /* Special case for zero sized packets.*/
+ osp->rxpkts = 1;
+ else
+ osp->rxpkts = (uint16_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) /
+ usbp->epc[ep]->out_maxsize);
+
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
+}
+
+/**
+ * @brief Starts a transmit operation on an IN endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
+ size_t n;
+ USBInEndpointState *isp = usbp->epc[ep]->in_state;
+
+ /* Transfer initialization.*/
+ n = isp->txsize;
+ if (n > (size_t)usbp->epc[ep]->in_maxsize)
+ n = (size_t)usbp->epc[ep]->in_maxsize;
+
+ isp->txlast = n;
+ usb_packet_write_from_buffer(ep, isp->txbuf, n);
+
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
+}
+
+/**
+ * @brief Brings an OUT endpoint in the stalled state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_STALL);
+}
+
+/**
+ * @brief Brings an IN endpoint in the stalled state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_STALL);
+}
+
+/**
+ * @brief Brings an OUT endpoint in the active state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+
+ /* Makes sure to not put to NAK an endpoint that is already
+ transferring.*/
+ if ((STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) != EPR_STAT_RX_VALID)
+ EPR_SET_STAT_TX(ep, EPR_STAT_RX_NAK);
+}
+
+/**
+ * @brief Brings an IN endpoint in the active state.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+
+ /* Makes sure to not put to NAK an endpoint that is already
+ transferring.*/
+ if ((STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) != EPR_STAT_TX_VALID)
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_NAK);
+}
+
+#endif /* HAL_USE_USB */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h new file mode 100644 index 0000000..1270172 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/hal_usb_lld.h @@ -0,0 +1,521 @@ +/*
+ 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 USBv1/hal_usb_lld.h
+ * @brief STM32 USB subsystem low level driver header.
+ *
+ * @addtogroup USB
+ * @{
+ */
+
+#ifndef HAL_USB_LLD_H
+#define HAL_USB_LLD_H
+
+#if HAL_USE_USB || defined(__DOXYGEN__)
+
+#include "stm32_usb.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Maximum endpoint address.
+ */
+#define USB_MAX_ENDPOINTS USB_ENDOPOINTS_NUMBER
+
+/**
+ * @brief Status stage handling method.
+ */
+#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_SW
+
+/**
+ * @brief This device requires the address change after the status packet.
+ */
+#define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS
+
+/**
+ * @brief Method for set address acknowledge.
+ */
+#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief USB1 driver enable switch.
+ * @details If set to @p TRUE the support for USB1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_USB_USE_USB1) || defined(__DOXYGEN__)
+#define STM32_USB_USE_USB1 FALSE
+#endif
+
+/**
+ * @brief Enables the USB device low power mode on suspend.
+ */
+#if !defined(STM32_USB_LOW_POWER_ON_SUSPEND) || defined(__DOXYGEN__)
+#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE
+#endif
+
+/**
+ * @brief USB1 interrupt priority level setting.
+ */
+#if (!defined(STM32_USB_USB1_HP_IRQ_PRIORITY) && \
+ (STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER)) || defined(__DOXYGEN__)
+#define STM32_USB_USB1_HP_IRQ_PRIORITY 13
+#endif
+
+/**
+ * @brief USB1 interrupt priority level setting.
+ */
+#if !defined(STM32_USB_USB1_LP_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_USB_USB1_LP_IRQ_PRIORITY 14
+#endif
+
+/**
+ * @brief Enables isochronous support.
+ * @note Isochronous support requires special handling and this makes the
+ * code size increase significantly.
+ */
+#if !defined(STM32_USB_USE_ISOCHRONOUS) || defined(__DOXYGEN__)
+#define STM32_USB_USE_ISOCHRONOUS FALSE
+#endif
+
+/**
+ * @brief Use faster copy for packets.
+ * @note Makes the driver larger.
+ */
+#if !defined(STM32_USB_USE_FAST_COPY) || defined(__DOXYGEN__)
+#define STM32_USB_USE_FAST_COPY FALSE
+#endif
+
+/**
+ * @brief Host wake-up procedure duration.
+ */
+#if !defined(STM32_USB_HOST_WAKEUP_DURATION) || defined(__DOXYGEN__)
+#define STM32_USB_HOST_WAKEUP_DURATION 2
+#endif
+
+/**
+ * @brief Allowed deviation for the 48MHz clock.
+ */
+#if !defined(STM32_USB_48MHZ_DELTA) || defined(__DOXYGEN__)
+#define STM32_USB_48MHZ_DELTA 0
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_USB_USE_USB1 && !STM32_HAS_USB
+#error "USB not present in the selected device"
+#endif
+
+#if !STM32_USB_USE_USB1
+#error "USB driver activated but no USB peripheral assigned"
+#endif
+
+#if STM32_USB_USE_USB1 && \
+ (STM32_USB1_HP_NUMBER != STM32_USB1_LP_NUMBER) && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_USB1_HP_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USB HP"
+#endif
+
+#if STM32_USB_USE_USB1 && \
+ !OSAL_IRQ_IS_VALID_PRIORITY(STM32_USB_USB1_LP_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to USB LP"
+#endif
+
+#if !defined(STM32_USB1_HP_HANDLER)
+#error "STM32_USB1_HP_HANDLER not defined"
+#endif
+
+#if !defined(STM32_USB1_HP_NUMBER)
+#error "STM32_USB1_HP_NUMBER not defined"
+#endif
+
+#if !defined(STM32_USB1_LP_HANDLER)
+#error "STM32_USB1_LP_HANDLER not defined"
+#endif
+
+#if !defined(STM32_USB1_LP_NUMBER)
+#error "STM32_USB1_LP_NUMBER not defined"
+#endif
+
+#if (STM32_USB_HOST_WAKEUP_DURATION < 2) || (STM32_USB_HOST_WAKEUP_DURATION > 15)
+#error "invalid STM32_USB_HOST_WAKEUP_DURATION setting, it must be between 2 and 15"
+#endif
+
+#if (STM32_USB_48MHZ_DELTA < 0) || (STM32_USB_48MHZ_DELTA > 250000)
+#error "invalid STM32_USB_48MHZ_DELTA setting, it must not exceed 250000"
+#endif
+
+#if (STM32_USBCLK < (48000000 - STM32_USB_48MHZ_DELTA)) || \
+ (STM32_USBCLK > (48000000 + STM32_USB_48MHZ_DELTA))
+#error "the USB driver requires a 48MHz clock"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of an IN endpoint state structure.
+ */
+typedef struct {
+ /**
+ * @brief Requested transmit transfer size.
+ */
+ size_t txsize;
+ /**
+ * @brief Transmitted bytes so far.
+ */
+ size_t txcnt;
+ /**
+ * @brief Pointer to the transmission linear buffer.
+ */
+ const uint8_t *txbuf;
+#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ thread_reference_t thread;
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Size of the last transmitted packet.
+ */
+ size_t txlast;
+} USBInEndpointState;
+
+/**
+ * @brief Type of an OUT endpoint state structure.
+ */
+typedef struct {
+ /**
+ * @brief Requested receive transfer size.
+ */
+ size_t rxsize;
+ /**
+ * @brief Received bytes so far.
+ */
+ size_t rxcnt;
+ /**
+ * @brief Pointer to the receive linear buffer.
+ */
+ uint8_t *rxbuf;
+#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ thread_reference_t thread;
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Number of packets to receive.
+ */
+ uint16_t rxpkts;
+} USBOutEndpointState;
+
+/**
+ * @brief Type of an USB endpoint configuration structure.
+ * @note Platform specific restrictions may apply to endpoints.
+ */
+typedef struct {
+ /**
+ * @brief Type and mode of the endpoint.
+ */
+ uint32_t ep_mode;
+ /**
+ * @brief Setup packet notification callback.
+ * @details This callback is invoked when a setup packet has been
+ * received.
+ * @post The application must immediately call @p usbReadPacket() in
+ * order to access the received packet.
+ * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL
+ * endpoints, it should be set to @p NULL for other endpoint
+ * types.
+ */
+ usbepcallback_t setup_cb;
+ /**
+ * @brief IN endpoint notification callback.
+ * @details This field must be set to @p NULL if callback is not required.
+ */
+ usbepcallback_t in_cb;
+ /**
+ * @brief OUT endpoint notification callback.
+ * @details This field must be set to @p NULL if callback is not required.
+ */
+ usbepcallback_t out_cb;
+ /**
+ * @brief IN endpoint maximum packet size.
+ * @details This field must be set to zero if the IN endpoint is not used.
+ */
+ uint16_t in_maxsize;
+ /**
+ * @brief OUT endpoint maximum packet size.
+ * @details This field must be set to zero if the OUT endpoint is not used.
+ */
+ uint16_t out_maxsize;
+ /**
+ * @brief @p USBEndpointState associated to the IN endpoint.
+ * @details This field must be set to @p NULL if the IN endpoint is not
+ * used.
+ */
+ USBInEndpointState *in_state;
+ /**
+ * @brief @p USBEndpointState associated to the OUT endpoint.
+ * @details This field must be set to @p NULL if the OUT endpoint is not
+ * used.
+ */
+ USBOutEndpointState *out_state;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Reserved field, not currently used.
+ * @note Initialize this field to 1 in order to be forward compatible.
+ */
+ uint16_t ep_buffers;
+ /**
+ * @brief Pointer to a buffer for setup packets.
+ * @details Setup packets require a dedicated 8-bytes buffer, set this
+ * field to @p NULL for non-control endpoints.
+ */
+ uint8_t *setup_buf;
+} USBEndpointConfig;
+
+/**
+ * @brief Type of an USB driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief USB events callback.
+ * @details This callback is invoked when an USB driver event is registered.
+ */
+ usbeventcb_t event_cb;
+ /**
+ * @brief Device GET_DESCRIPTOR request callback.
+ * @note This callback is mandatory and cannot be set to @p NULL.
+ */
+ usbgetdescriptor_t get_descriptor_cb;
+ /**
+ * @brief Requests hook callback.
+ * @details This hook allows to be notified of standard requests or to
+ * handle non standard requests.
+ */
+ usbreqhandler_t requests_hook_cb;
+ /**
+ * @brief Start Of Frame callback.
+ */
+ usbcallback_t sof_cb;
+ /* End of the mandatory fields.*/
+} USBConfig;
+
+/**
+ * @brief Structure representing an USB driver.
+ */
+struct USBDriver {
+ /**
+ * @brief Driver state.
+ */
+ usbstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const USBConfig *config;
+ /**
+ * @brief Bit map of the transmitting IN endpoints.
+ */
+ uint16_t transmitting;
+ /**
+ * @brief Bit map of the receiving OUT endpoints.
+ */
+ uint16_t receiving;
+ /**
+ * @brief Active endpoints configurations.
+ */
+ const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1];
+ /**
+ * @brief Fields available to user, it can be used to associate an
+ * application-defined handler to an IN endpoint.
+ * @note The base index is one, the endpoint zero does not have a
+ * reserved element in this array.
+ */
+ void *in_params[USB_MAX_ENDPOINTS];
+ /**
+ * @brief Fields available to user, it can be used to associate an
+ * application-defined handler to an OUT endpoint.
+ * @note The base index is one, the endpoint zero does not have a
+ * reserved element in this array.
+ */
+ void *out_params[USB_MAX_ENDPOINTS];
+ /**
+ * @brief Endpoint 0 state.
+ */
+ usbep0state_t ep0state;
+ /**
+ * @brief Next position in the buffer to be transferred through endpoint 0.
+ */
+ uint8_t *ep0next;
+ /**
+ * @brief Number of bytes yet to be transferred through endpoint 0.
+ */
+ size_t ep0n;
+ /**
+ * @brief Endpoint 0 end transaction callback.
+ */
+ usbcallback_t ep0endcb;
+ /**
+ * @brief Setup packet buffer.
+ */
+ uint8_t setup[8];
+ /**
+ * @brief Current USB device status.
+ */
+ uint16_t status;
+ /**
+ * @brief Assigned USB address.
+ */
+ uint8_t address;
+ /**
+ * @brief Current USB device configuration.
+ */
+ uint8_t configuration;
+ /**
+ * @brief State of the driver when a suspend happened.
+ */
+ usbstate_t saved_state;
+#if defined(USB_DRIVER_EXT_FIELDS)
+ USB_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the next address in the packet memory.
+ */
+ uint32_t pmnext;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Returns the current frame number.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @return The current frame number.
+ *
+ * @notapi
+ */
+#define usb_lld_get_frame_number(usbp) (STM32_USB->FNR & FNR_FN_MASK)
+
+/**
+ * @brief Returns the exact size of a receive transaction.
+ * @details The received size can be different from the size specified in
+ * @p usbStartReceiveI() because the last packet could have a size
+ * different from the expected one.
+ * @pre The OUT endpoint must have been configured in transaction mode
+ * in order to use this function.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return Received data size.
+ *
+ * @notapi
+ */
+#define usb_lld_get_transaction_size(usbp, ep) \
+ ((usbp)->epc[ep]->out_state->rxcnt)
+
+#if STM32_USB_HAS_BCDR || defined(__DOXYGEN__)
+/**
+ * @brief Connects the USB device.
+ *
+ * @notapi
+ */
+#if !defined(usb_lld_connect_bus)
+#define usb_lld_connect_bus(usbp) (STM32_USB->BCDR |= USB_BCDR_DPPU)
+#endif
+
+/**
+ * @brief Disconnect the USB device.
+ *
+ * @notapi
+ */
+#if !defined(usb_lld_disconnect_bus)
+#define usb_lld_disconnect_bus(usbp) (STM32_USB->BCDR &= ~USB_BCDR_DPPU)
+#endif
+#endif /* STM32_USB_HAS_BCDR */
+
+#if defined(STM32L1XX)
+#if !defined(usb_lld_connect_bus)
+#define usb_lld_connect_bus(usbp) (SYSCFG->PMC |= SYSCFG_PMC_USB_PU)
+#endif
+
+#if !defined(usb_lld_disconnect_bus)
+#define usb_lld_disconnect_bus(usbp) (SYSCFG->PMC &= ~SYSCFG_PMC_USB_PU)
+#endif
+#endif /* STM32L1XX */
+
+/**
+ * @brief Start of host wake-up procedure.
+ *
+ * @notapi
+ */
+#define usb_lld_wakeup_host(usbp) \
+ do { \
+ STM32_USB->CNTR |= USB_CNTR_RESUME; \
+ osalThreadSleepMilliseconds(STM32_USB_HOST_WAKEUP_DURATION); \
+ STM32_USB->CNTR &= ~USB_CNTR_RESUME; \
+ } while (false)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_USB_USE_USB1 && !defined(__DOXYGEN__)
+extern USBDriver USBD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void usb_lld_init(void);
+ void usb_lld_start(USBDriver *usbp);
+ void usb_lld_stop(USBDriver *usbp);
+ void usb_lld_reset(USBDriver *usbp);
+ void usb_lld_set_address(USBDriver *usbp);
+ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
+ void usb_lld_disable_endpoints(USBDriver *usbp);
+ usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
+ usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
+ void usb_lld_start_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_start_in(USBDriver *usbp, usbep_t ep);
+ void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
+ void usb_lld_clear_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_USB */
+
+#endif /* HAL_USB_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h new file mode 100644 index 0000000..9a8595e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/USBv1/stm32_usb.h @@ -0,0 +1,266 @@ +/*
+ 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 USBv1/stm32_usb.h
+ * @brief STM32 USB registers layout header.
+ * @note This file requires definitions from the ST STM32 header files
+ * stm32f10x.h or stm32l1xx.h.
+ *
+ * @addtogroup USB
+ * @{
+ */
+
+#ifndef STM32_USB_H
+#define STM32_USB_H
+
+/**
+ * @brief Number of the available endpoints.
+ * @details This value does not include the endpoint 0 which is always present.
+ */
+#define USB_ENDOPOINTS_NUMBER 7
+
+/**
+ * @brief Width of USB packet memory accesses.
+ */
+#if STM32_USB_ACCESS_SCHEME_2x16
+typedef uint16_t stm32_usb_pma_t;
+#else
+typedef uint32_t stm32_usb_pma_t;
+#endif
+
+/**
+ * @brief USB registers block.
+ */
+typedef struct {
+ /**
+ * @brief Endpoint registers.
+ */
+ volatile uint32_t EPR[USB_ENDOPOINTS_NUMBER + 1];
+ /*
+ * @brief Reserved space.
+ */
+ volatile uint32_t _r20[8];
+ /*
+ * @brief Control Register.
+ */
+ volatile uint32_t CNTR;
+ /*
+ * @brief Interrupt Status Register.
+ */
+ volatile uint32_t ISTR;
+ /*
+ * @brief Frame Number Register.
+ */
+ volatile uint32_t FNR;
+ /*
+ * @brief Device Address Register.
+ */
+ volatile uint32_t DADDR;
+ /*
+ * @brief Buffer Table Address.
+ */
+ volatile uint32_t BTABLE;
+ /*
+ * @brief LPM Control and Status Register.
+ */
+ volatile uint32_t LPMCSR;
+#if STM32_USB_HAS_BCDR
+ /*
+ * @brief Battery Charging Detector
+ */
+ volatile uint32_t BCDR;
+#endif
+} stm32_usb_t;
+
+/**
+ * @brief USB descriptor registers block.
+ */
+typedef struct {
+ /**
+ * @brief TX buffer offset register.
+ */
+ volatile stm32_usb_pma_t TXADDR0;
+ /**
+ * @brief TX counter register 0.
+ */
+ volatile stm32_usb_pma_t TXCOUNT0;
+ /**
+ * @brief RX buffer offset register.
+ */
+ volatile stm32_usb_pma_t RXADDR0;
+ /**
+ * @brief RX counter register 0.
+ */
+ volatile stm32_usb_pma_t RXCOUNT0;
+} stm32_usb_descriptor_t;
+
+/**
+ * @name Register aliases
+ * @{
+ */
+#define RXCOUNT1 TXCOUNT0
+#define TXCOUNT1 RXCOUNT0
+#define RXADDR1 TXADDR0
+#define TXADDR1 RXADDR0
+/** @} */
+
+/**
+ * @brief USB registers block numeric address.
+ */
+#if defined(USB_BASE) || defined(__DOXYGEN__)
+#define STM32_USB_BASE USB_BASE
+#else
+#define STM32_USB_BASE (APB1PERIPH_BASE + 0x5C00)
+#endif
+
+/**
+ * @brief USB RAM numeric address.
+ */
+#if defined(USB_PMAADDR) || defined(__DOXYGEN__)
+#define STM32_USBRAM_BASE USB_PMAADDR
+#else
+#define STM32_USBRAM_BASE (APB1PERIPH_BASE + 0x6000)
+#endif
+
+/**
+ * @brief Pointer to the USB registers block.
+ */
+#define STM32_USB ((stm32_usb_t *)STM32_USB_BASE)
+
+/**
+ * @brief Pointer to the USB RAM.
+ */
+#define STM32_USBRAM ((stm32_usb_pma_t *)STM32_USBRAM_BASE)
+
+/**
+ * @brief Mask of all the toggling bits in the EPR register.
+ */
+#define EPR_TOGGLE_MASK (EPR_STAT_TX_MASK | EPR_DTOG_TX | \
+ EPR_STAT_RX_MASK | EPR_DTOG_RX | \
+ EPR_SETUP)
+
+#define EPR_EA_MASK 0x000F
+#define EPR_STAT_TX_MASK 0x0030
+#define EPR_STAT_TX_DIS 0x0000
+#define EPR_STAT_TX_STALL 0x0010
+#define EPR_STAT_TX_NAK 0x0020
+#define EPR_STAT_TX_VALID 0x0030
+#define EPR_DTOG_TX 0x0040
+#define EPR_SWBUF_RX EPR_DTOG_TX
+#define EPR_CTR_TX 0x0080
+#define EPR_EP_KIND 0x0100
+#define EPR_EP_DBL_BUF EPR_EP_KIND
+#define EPR_EP_STATUS_OUT EPR_EP_KIND
+#define EPR_EP_TYPE_MASK 0x0600
+#define EPR_EP_TYPE_BULK 0x0000
+#define EPR_EP_TYPE_CONTROL 0x0200
+#define EPR_EP_TYPE_ISO 0x0400
+#define EPR_EP_TYPE_INTERRUPT 0x0600
+#define EPR_SETUP 0x0800
+#define EPR_STAT_RX_MASK 0x3000
+#define EPR_STAT_RX_DIS 0x0000
+#define EPR_STAT_RX_STALL 0x1000
+#define EPR_STAT_RX_NAK 0x2000
+#define EPR_STAT_RX_VALID 0x3000
+#define EPR_DTOG_RX 0x4000
+#define EPR_SWBUF_TX EPR_DTOG_RX
+#define EPR_CTR_RX 0x8000
+
+#define CNTR_FRES 0x0001
+#define CNTR_PDWN 0x0002
+#define CNTR_LP_MODE 0x0004
+#define CNTR_FSUSP 0x0008
+#define CNTR_RESUME 0x0010
+#define CNTR_ESOFM 0x0100
+#define CNTR_SOFM 0x0200
+#define CNTR_RESETM 0x0400
+#define CNTR_SUSPM 0x0800
+#define CNTR_WKUPM 0x1000
+#define CNTR_ERRM 0x2000
+#define CNTR_PMAOVRM 0x4000
+#define CNTR_CTRM 0x8000
+
+#define ISTR_EP_ID_MASK 0x000F
+#define ISTR_DIR 0x0010
+#define ISTR_ESOF 0x0100
+#define ISTR_SOF 0x0200
+#define ISTR_RESET 0x0400
+#define ISTR_SUSP 0x0800
+#define ISTR_WKUP 0x1000
+#define ISTR_ERR 0x2000
+#define ISTR_PMAOVR 0x4000
+#define ISTR_CTR 0x8000
+
+#define FNR_FN_MASK 0x07FF
+#define FNR_LSOF 0x1800
+#define FNR_LCK 0x2000
+#define FNR_RXDM 0x4000
+#define FNR_RXDP 0x8000
+
+#define DADDR_ADD_MASK 0x007F
+#define DADDR_EF 0x0080
+
+#define RXCOUNT_COUNT_MASK 0x03FF
+#define TXCOUNT_COUNT_MASK 0x03FF
+
+#define EPR_CTR_MASK (EPR_CTR_TX | EPR_CTR_RX)
+
+#define EPR_SET(ep, epr) \
+ STM32_USB->EPR[ep] = ((epr) & ~EPR_TOGGLE_MASK) | EPR_CTR_MASK
+
+#define EPR_TOGGLE(ep, epr) \
+ STM32_USB->EPR[ep] = (STM32_USB->EPR[ep] ^ ((epr) & EPR_TOGGLE_MASK)) \
+ | EPR_CTR_MASK
+
+#define EPR_SET_STAT_RX(ep, epr) \
+ STM32_USB->EPR[ep] = ((STM32_USB->EPR[ep] & \
+ ~(EPR_TOGGLE_MASK & ~EPR_STAT_RX_MASK)) ^ \
+ (epr)) | EPR_CTR_MASK
+
+#define EPR_SET_STAT_TX(ep, epr) \
+ STM32_USB->EPR[ep] = ((STM32_USB->EPR[ep] & \
+ ~(EPR_TOGGLE_MASK & ~EPR_STAT_TX_MASK)) ^ \
+ (epr)) | EPR_CTR_MASK
+
+#define EPR_CLEAR_CTR_RX(ep) \
+ STM32_USB->EPR[ep] = (STM32_USB->EPR[ep] & ~EPR_CTR_RX & ~EPR_TOGGLE_MASK)\
+ | EPR_CTR_TX
+
+#define EPR_CLEAR_CTR_TX(ep) \
+ STM32_USB->EPR[ep] = (STM32_USB->EPR[ep] & ~EPR_CTR_TX & ~EPR_TOGGLE_MASK)\
+ | EPR_CTR_RX
+
+/**
+ * @brief Returns an endpoint descriptor pointer.
+ */
+#define USB_GET_DESCRIPTOR(ep) \
+ ((stm32_usb_descriptor_t *)((uint32_t)STM32_USBRAM_BASE + \
+ (uint32_t)STM32_USB->BTABLE + \
+ (uint32_t)(ep) * \
+ sizeof(stm32_usb_descriptor_t)))
+
+/**
+ * @brief Converts from a PMA address to a physical address.
+ */
+#define USB_ADDR2PTR(addr) \
+ ((stm32_usb_pma_t *)((addr) * \
+ (sizeof(stm32_usb_pma_t) / 2) + \
+ STM32_USBRAM_BASE))
+
+#endif /* STM32_USB_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk new file mode 100644 index 0000000..a4d8bdd --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes)
+ifneq ($(findstring HAL_USE_WDG TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c
+endif
+else
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c
+endif
+
+PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c new file mode 100644 index 0000000..42a620e --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.c @@ -0,0 +1,144 @@ +/*
+ 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 xWDGv1/hal_wdg_lld.c
+ * @brief WDG Driver subsystem low level driver source.
+ *
+ * @addtogroup WDG
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define KR_KEY_RELOAD 0xAAAAU
+#define KR_KEY_ENABLE 0xCCCCU
+#define KR_KEY_WRITE 0x5555U
+#define KR_KEY_PROTECT 0x0000U
+
+#if !defined(IWDG) && defined(IWDG1)
+#define IWDG IWDG1
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+#if STM32_WDG_USE_IWDG || defined(__DOXYGEN__)
+WDGDriver WDGD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level WDG driver initialization.
+ *
+ * @notapi
+ */
+void wdg_lld_init(void) {
+
+#if STM32_WDG_USE_IWDG
+ WDGD1.state = WDG_STOP;
+ WDGD1.wdg = IWDG;
+#endif
+}
+
+/**
+ * @brief Configures and activates the WDG peripheral.
+ *
+ * @param[in] wdgp pointer to the @p WDGDriver object
+ *
+ * @notapi
+ */
+void wdg_lld_start(WDGDriver *wdgp) {
+
+#if STM32_IWDG_IS_WINDOWED
+ /* Enable IWDG and unlock for write.*/
+ wdgp->wdg->KR = KR_KEY_ENABLE;
+ wdgp->wdg->KR = KR_KEY_WRITE;
+
+ /* Write configuration.*/
+ wdgp->wdg->PR = wdgp->config->pr;
+ wdgp->wdg->RLR = wdgp->config->rlr;
+ while (wdgp->wdg->SR != 0)
+ ;
+
+ /* This also triggers a refresh.*/
+ wdgp->wdg->WINR = wdgp->config->winr;
+#else
+ /* Unlock IWDG.*/
+ wdgp->wdg->KR = KR_KEY_WRITE;
+
+ /* Write configuration.*/
+ while (wdgp->wdg->SR != 0)
+ ;
+ wdgp->wdg->PR = wdgp->config->pr;
+ wdgp->wdg->RLR = wdgp->config->rlr;
+
+ /* Start operations.*/
+ wdgp->wdg->KR = KR_KEY_RELOAD;
+ wdgp->wdg->KR = KR_KEY_ENABLE;
+#endif
+}
+
+/**
+ * @brief Deactivates the WDG peripheral.
+ *
+ * @param[in] wdgp pointer to the @p WDGDriver object
+ *
+ * @notapi
+ */
+void wdg_lld_stop(WDGDriver *wdgp) {
+
+ osalDbgAssert(wdgp->state == WDG_STOP,
+ "IWDG cannot be stopped once activated");
+}
+
+/**
+ * @brief Reloads WDG's counter.
+ *
+ * @param[in] wdgp pointer to the @p WDGDriver object
+ *
+ * @notapi
+ */
+void wdg_lld_reset(WDGDriver * wdgp) {
+
+ wdgp->wdg->KR = KR_KEY_RELOAD;
+}
+
+#endif /* HAL_USE_WDG == TRUE */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h new file mode 100644 index 0000000..7528899 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/LLD/xWDGv1/hal_wdg_lld.h @@ -0,0 +1,183 @@ +/*
+ 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 xWDGv1/hal_wdg_lld.h
+ * @brief WDG Driver subsystem low level driver header.
+ *
+ * @addtogroup WDG
+ * @{
+ */
+
+#ifndef HAL_WDG_LLD_H
+#define HAL_WDG_LLD_H
+
+#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name RLR register definitions
+ * @{
+ */
+#define STM32_IWDG_RL_MASK (0x00000FFF << 0)
+#define STM32_IWDG_RL(n) ((n) << 0)
+/** @} */
+
+/**
+ * @name PR register definitions
+ * @{
+ */
+#define STM32_IWDG_PR_MASK (7 << 0)
+#define STM32_IWDG_PR_4 0U
+#define STM32_IWDG_PR_8 1U
+#define STM32_IWDG_PR_16 2U
+#define STM32_IWDG_PR_32 3U
+#define STM32_IWDG_PR_64 4U
+#define STM32_IWDG_PR_128 5U
+#define STM32_IWDG_PR_256 6U
+/** @} */
+
+/**
+ * @name WINR register definitions
+ * @{
+ */
+#define STM32_IWDG_WIN_MASK (0x00000FFF << 0)
+#define STM32_IWDG_WIN(n) ((n) << 0)
+#define STM32_IWDG_WIN_DISABLED STM32_IWDG_WIN(0x00000FFF)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief IWDG driver enable switch.
+ * @details If set to @p TRUE the support for IWDG is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_WDG_USE_IWDG) || defined(__DOXYGEN__)
+#define STM32_WDG_USE_IWDG FALSE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_WDG_USE_IWDG && !STM32_HAS_IWDG
+#error "IWDG not present in the selected device"
+#endif
+
+#if !STM32_WDG_USE_IWDG
+#error "WDG driver activated but no xWDG peripheral assigned"
+#endif
+
+#if !defined(STM32_LSI_ENABLED)
+#error "STM32_LSI_ENABLED not defined"
+#endif
+
+#if (STM32_WDG_USE_IWDG == TRUE) && (STM32_LSI_ENABLED == FALSE)
+#error "IWDG requires LSI clock"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an WDG driver.
+ */
+typedef struct WDGDriver WDGDriver;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Configuration of the IWDG_PR register.
+ * @details See the STM32 reference manual for details.
+ */
+ uint32_t pr;
+ /**
+ * @brief Configuration of the IWDG_RLR register.
+ * @details See the STM32 reference manual for details.
+ */
+ uint32_t rlr;
+#if STM32_IWDG_IS_WINDOWED || defined(__DOXYGEN__)
+ /**
+ * @brief Configuration of the IWDG_WINR register.
+ * @details See the STM32 reference manual for details.
+ * @note This field is not present in F1, F2, F4, L1 sub-families.
+ */
+ uint32_t winr;
+#endif
+} WDGConfig;
+
+/**
+ * @brief Structure representing an WDG driver.
+ */
+struct WDGDriver {
+ /**
+ * @brief Driver state.
+ */
+ wdgstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const WDGConfig *config;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the IWDG registers block.
+ */
+ IWDG_TypeDef *wdg;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_WDG_USE_IWDG && !defined(__DOXYGEN__)
+extern WDGDriver WDGD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void wdg_lld_init(void);
+ void wdg_lld_start(WDGDriver *wdgp);
+ void wdg_lld_stop(WDGDriver *wdgp);
+ void wdg_lld_reset(WDGDriver *wdgp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_WDG == TRUE */
+
+#endif /* HAL_WDG_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c new file mode 100644 index 0000000..e9ffb25 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.c @@ -0,0 +1,452 @@ +/*
+ 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 STM32H7xx/hal_lld.c
+ * @brief STM32H7xx HAL subsystem low level driver source.
+ *
+ * @addtogroup HAL
+ * @{
+ */
+
+#include "hal.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief CMSIS system core clock variable.
+ * @note It is declared in system_stm32f7xx.h.
+ */
+uint32_t SystemCoreClock = STM32_CORE_CK;
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initializes the backup domain.
+ * @note WARNING! Changing clock source impossible without resetting
+ * of the whole BKP domain.
+ */
+static inline void init_bkp_domain(void) {
+
+ /* Backup domain access enabled and left open.*/
+ PWR->CR1 |= PWR_CR1_DBP;
+
+ /* Reset BKP domain if different clock source selected.*/
+ if ((RCC->BDCR & STM32_RTCSEL_MASK) != STM32_RTCSEL) {
+ /* Backup domain reset.*/
+ RCC->BDCR = RCC_BDCR_BDRST;
+ RCC->BDCR = 0;
+ }
+
+#if STM32_LSE_ENABLED
+#if defined(STM32_LSE_BYPASS)
+ /* LSE Bypass.*/
+ RCC->BDCR |= STM32_LSEDRV | RCC_BDCR_LSEON | RCC_BDCR_LSEBYP;
+#else
+ /* No LSE Bypass.*/
+ RCC->BDCR |= STM32_LSEDRV | RCC_BDCR_LSEON;
+#endif
+ while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0)
+ ; /* Waits until LSE is stable. */
+#endif
+
+#if HAL_USE_RTC
+ /* If the backup domain hasn't been initialized yet then proceed with
+ initialization.*/
+ if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0) {
+ /* Selects clock source.*/
+ RCC->BDCR |= STM32_RTCSEL;
+
+ /* RTC clock enabled.*/
+ RCC->BDCR |= RCC_BDCR_RTCEN;
+ }
+#endif /* HAL_USE_RTC */
+}
+
+/**
+ * @brief Initializes the PWR unit.
+ */
+static inline void init_pwr(void) {
+#if 0
+ PWR_TypeDef *pwr = PWR; /* For inspection.*/
+ (void)pwr;
+#endif
+
+ /* Lower C3 byte, it must be programmed at very first, then waiting for
+ power supply to stabilize.*/
+ PWR->CR3 = STM32_PWR_CR3 & 0x000000FFU;
+ while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0)
+ ; /* CHTODO timeout handling.*/
+
+ PWR->CR1 = STM32_PWR_CR1 | 0xF0000000U;
+ PWR->CR2 = STM32_PWR_CR2;
+ PWR->CR3 = STM32_PWR_CR3; /* Other bits, lower byte is not changed. */
+ PWR->CPUCR = STM32_PWR_CPUCR;
+ PWR->D3CR = STM32_VOS;
+#if !defined(STM32_ENFORCE_H7_REV_XY) && !defined(STM32H723xx)
+ SYSCFG->PWRCR = STM32_ODEN;
+#endif
+ while ((PWR->D3CR & PWR_D3CR_VOSRDY) == 0)
+ ; /* CHTODO timeout handling.*/
+#if STM32_PWR_CR2 & PWR_CR2_BREN
+// while ((PWR->CR2 & PWR_CR2_BRRDY) == 0)
+// ;
+// rccEnableBKPRAM(true);
+#endif
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level HAL driver initialization.
+ *
+ * @notapi
+ */
+void hal_lld_init(void) {
+
+#if STM32_NO_INIT == FALSE
+ /* Reset of all peripherals. AHB3 is not reset entirely because FMC could
+ have been initialized in the board initialization file (board.c).
+ Note, GPIOs are not reset because initialized before this point in
+ board files.*/
+ rccResetAHB1(~0);
+ rccResetAHB2(~0);
+ rccResetAHB3(~(RCC_AHB3RSTR_FMCRST |
+ 0x80000000U)); /* Was RCC_AHB3RSTR_CPURST in Rev-V.*/
+ rccResetAHB4(~(RCC_APB4RSTR_SYSCFGRST | STM32_GPIO_EN_MASK));
+ rccResetAPB1L(~0);
+ rccResetAPB1H(~0);
+ rccResetAPB2(~0);
+ rccResetAPB3(~0);
+ rccResetAPB4(~0);
+#endif /* STM32_NO_INIT == FALSE */
+
+ /* DMA subsystems initialization.*/
+#if defined(STM32_BDMA_REQUIRED)
+ bdmaInit();
+#endif
+#if defined(STM32_DMA_REQUIRED)
+ dmaInit();
+#endif
+#if defined(STM32_MDMA_REQUIRED)
+ mdmaInit();
+#endif
+
+ /* IRQ subsystem initialization.*/
+ irqInit();
+
+ /* MPU initialization.*/
+#if (STM32_NOCACHE_SRAM1_SRAM2 == TRUE) || (STM32_NOCACHE_SRAM3 == TRUE) || \
+ (STM32_NOCACHE_SRAM4 == TRUE)
+ {
+ uint32_t base, size;
+
+#if (STM32_NOCACHE_SRAM1_SRAM2 == TRUE) && (STM32_NOCACHE_SRAM3 == TRUE)
+ base = 0x30000000U;
+ size = MPU_RASR_SIZE_512K;
+#elif (STM32_NOCACHE_SRAM1_SRAM2 == TRUE) && (STM32_NOCACHE_SRAM3 == FALSE)
+ base = 0x30000000U;
+ size = MPU_RASR_SIZE_256K;
+#elif (STM32_NOCACHE_SRAM1_SRAM2 == FALSE) && (STM32_NOCACHE_SRAM3 == TRUE)
+ base = 0x30040000U;
+ size = MPU_RASR_SIZE_16K;
+#elif (STM32_NOCACHE_SRAM4 == TRUE)
+ base = 0x38000000U;
+ size = MPU_RASR_SIZE_16K;
+#else
+#error "invalid constants used in mcuconf.h"
+#endif
+
+ /* The SRAM2 bank can optionally made a non cache-able area for use by
+ DMA engines.*/
+ mpuConfigureRegion(STM32_NOCACHE_MPU_REGION,
+ base,
+ MPU_RASR_ATTR_AP_RW_RW |
+ MPU_RASR_ATTR_NON_CACHEABLE |
+ size |
+ MPU_RASR_ENABLE);
+ mpuEnable(MPU_CTRL_PRIVDEFENA);
+
+ /* Invalidating data cache to make sure that the MPU settings are taken
+ immediately.*/
+ SCB_CleanInvalidateDCache();
+ }
+#endif
+}
+
+/**
+ * @brief STM32H7xx clocks and PLL initialization.
+ * @note All the involved constants come from the file @p board.h.
+ * @note This function should be invoked just after the system reset.
+ *
+ * @special
+ */
+void stm32_clock_init(void) {
+#if STM32_NO_INIT == FALSE
+ uint32_t cfgr;
+
+#if 0
+ RCC_TypeDef *rcc = RCC; /* For inspection.*/
+ (void)rcc;
+#endif
+
+#if defined(STM32_ENFORCE_H7_REV_XY)
+ /* Fix for errata 2.2.15: Reading from AXI SRAM might lead to data
+ read corruption.
+ AXI->TARG7_FN_MOD.*/
+ *((volatile uint32_t *)(0x51000000 + 0x1108 + 0x7000)) = 0x00000001U;
+#endif
+
+ /* SYSCFG clock enabled here because it is a multi-functional unit shared
+ among multiple drivers.*/
+ rccEnableAPB4(RCC_APB4ENR_SYSCFGEN, true);
+
+ /* PWR initialization.*/
+ init_pwr();
+
+ /* Backup domain initialization.*/
+ init_bkp_domain();
+
+ /* HSI setup, it enforces the reset situation in order to handle possible
+ problems with JTAG probes and re-initializations.*/
+ RCC->CR |= RCC_CR_HSION; /* Make sure HSI is ON. */
+ while (!(RCC->CR & RCC_CR_HSIRDY))
+ ; /* Wait until HSI is stable. */
+
+ /* HSI is selected as new source without touching the other fields in
+ CFGR. This is only required when using a debugger than can cause
+ restarts.*/
+ RCC->CFGR = 0x00000000U; /* Reset SW to HSI. */
+ while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
+ ; /* Wait until HSI is selected. */
+
+ /* Registers cleared to reset values.*/
+#if STM32_HSI_ENABLED == FALSE
+ RCC->CR = RCC_CR_HSION; /* CR Reset value. */
+#else
+ RCC->CR = RCC_CR_HSION | STM32_HSIDIV; /* CR Reset value. */
+#endif
+ RCC->HSICFGR = 0x40000000U; /* HSICFGR Reset value. */
+#if !defined(STM32_ENFORCE_H7_REV_XY)
+ RCC->CSICFGR = 0x20000000U; /* CSICFGR Reset value. */
+#endif
+ RCC->CSR = 0x00000000U; /* CSR reset value. */
+ RCC->PLLCFGR = 0x01FF0000U; /* PLLCFGR reset value. */
+
+ /* Other clock-related settings, done before other things because
+ recommended in the RM.*/
+ cfgr = STM32_MCO2SEL | RCC_CFGR_MCO2PRE_VALUE(STM32_MCO2PRE_VALUE) |
+ STM32_MCO1SEL | RCC_CFGR_MCO1PRE_VALUE(STM32_MCO1PRE_VALUE) |
+ RCC_CFGR_RTCPRE_VALUE(STM32_RTCPRE_VALUE) |
+ STM32_HRTIMSEL | STM32_STOPKERWUCK | STM32_STOPWUCK;
+#if STM32_TIMPRE_ENABLE == TRUE
+ cfgr |= RCC_CFGR_TIMPRE;
+#endif
+ RCC->CFGR = cfgr;
+
+ /* HSE activation with optional bypass.*/
+#if STM32_HSE_ENABLED == TRUE
+#if defined(STM32_HSE_BYPASS)
+ RCC->CR |= RCC_CR_HSEON | RCC_CR_HSEBYP;
+#else
+ RCC->CR |= RCC_CR_HSEON;
+#endif
+ while ((RCC->CR & RCC_CR_HSERDY) == 0)
+ ; /* Waits until HSE is stable. */
+#endif /* STM32_HSE_ENABLED == TRUE */
+
+ /* HSI48 activation.*/
+#if STM32_HSI48_ENABLED == TRUE
+ RCC->CR |= RCC_CR_HSI48ON;
+ while ((RCC->CR & RCC_CR_HSI48RDY) == 0)
+ ; /* Waits until HSI48 is stable. */
+
+#endif /* STM32_HSI48_ENABLED == TRUE */
+
+ /* CSI activation.*/
+#if STM32_CSI_ENABLED == TRUE
+ RCC->CR |= RCC_CR_CSION;
+ while ((RCC->CR & RCC_CR_CSIRDY) == 0)
+ ; /* Waits until CSI is stable. */
+#endif /* STM32_CSI_ENABLED == TRUE */
+
+ /* LSI activation.*/
+#if STM32_LSI_ENABLED == TRUE
+ RCC->CSR |= RCC_CSR_LSION;
+ while ((RCC->CSR & RCC_CSR_LSIRDY) == 0)
+ ; /* Waits until LSI is stable. */
+#endif /* STM32_LSI_ENABLED == TRUE */
+
+ /* PLLs activation, it happens in parallel in order to
+ reduce boot time.*/
+#if (STM32_PLL1_ENABLED == TRUE) || \
+ (STM32_PLL2_ENABLED == TRUE) || \
+ (STM32_PLL3_ENABLED == TRUE)
+ {
+ uint32_t onmask = 0;
+ uint32_t rdymask = 0;
+ uint32_t cfgmask = 0;
+
+ RCC->PLLCKSELR = RCC_PLLCKSELR_DIVM3_VALUE(STM32_PLL3_DIVM_VALUE) |
+ RCC_PLLCKSELR_DIVM2_VALUE(STM32_PLL2_DIVM_VALUE) |
+ RCC_PLLCKSELR_DIVM1_VALUE(STM32_PLL1_DIVM_VALUE) |
+ RCC_PLLCKSELR_PLLSRC_VALUE(STM32_PLLSRC);
+
+ cfgmask = STM32_PLLCFGR_PLL3RGE | STM32_PLLCFGR_PLL3VCOSEL | RCC_PLLCFGR_PLL3FRACEN |
+ STM32_PLLCFGR_PLL2RGE | STM32_PLLCFGR_PLL2VCOSEL | RCC_PLLCFGR_PLL2FRACEN |
+ STM32_PLLCFGR_PLL1RGE | STM32_PLLCFGR_PLL1VCOSEL | RCC_PLLCFGR_PLL1FRACEN;
+
+#if STM32_PLL1_ENABLED == TRUE
+ RCC->PLL1FRACR = STM32_PLL1_FRACN;
+ RCC->PLL1DIVR = STM32_PLL1_DIVR | STM32_PLL1_DIVQ |
+ STM32_PLL1_DIVP | STM32_PLL1_DIVN;
+ onmask |= RCC_CR_PLL1ON;
+ rdymask |= RCC_CR_PLL1RDY;
+#if STM32_PLL1_P_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVP1EN;
+#endif
+#if STM32_PLL1_Q_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVQ1EN;
+#endif
+#if STM32_PLL1_R_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVR1EN;
+#endif
+#endif /* STM32_PLL1_ENABLED == TRUE */
+
+#if STM32_PLL2_ENABLED == TRUE
+ RCC->PLL2FRACR = STM32_PLL2_FRACN;
+ RCC->PLL2DIVR = STM32_PLL2_DIVR | STM32_PLL2_DIVQ |
+ STM32_PLL2_DIVP | STM32_PLL2_DIVN;
+ onmask |= RCC_CR_PLL2ON;
+ rdymask |= RCC_CR_PLL2RDY;
+#if STM32_PLL2_P_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVP2EN;
+#endif
+#if STM32_PLL2_Q_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVQ2EN;
+#endif
+#if STM32_PLL2_R_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVR2EN;
+#endif
+#endif /* STM32_PLL2_ENABLED == TRUE */
+
+#if STM32_PLL3_ENABLED == TRUE
+ RCC->PLL3FRACR = STM32_PLL3_FRACN;
+ RCC->PLL3DIVR = STM32_PLL3_DIVR | STM32_PLL3_DIVQ |
+ STM32_PLL3_DIVP | STM32_PLL3_DIVN;
+ onmask |= RCC_CR_PLL3ON;
+ rdymask |= RCC_CR_PLL3RDY;
+#if STM32_PLL3_P_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVP3EN;
+#endif
+#if STM32_PLL3_Q_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVQ3EN;
+#endif
+#if STM32_PLL3_R_ENABLED == TRUE
+ cfgmask |= RCC_PLLCFGR_DIVR3EN;
+#endif
+#endif /* STM32_PLL3_ENABLED == TRUE */
+
+ /* Activating enabled PLLs and waiting for all of them to become ready.*/
+ RCC->PLLCFGR = cfgmask & STM32_PLLCFGR_MASK;
+ RCC->CR |= onmask;
+ while ((RCC->CR & rdymask) != rdymask)
+ ;
+ }
+#endif /* STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED */
+
+ /* AHB and APB dividers.*/
+ RCC->D1CFGR = STM32_D1CPRE | STM32_D1PPRE3 | STM32_D1HPRE;
+ RCC->D2CFGR = STM32_D2PPRE2 | STM32_D2PPRE1;
+ RCC->D3CFGR = STM32_D3PPRE4;
+
+ /* Peripherals clocks.*/
+ RCC->D1CCIPR = STM32_CKPERSEL | STM32_SDMMCSEL
+#if !defined(STM32H723xx)
+ | STM32_QSPISEL | STM32_FMCSEL
+#endif
+ ;
+ RCC->D2CCIP1R = STM32_SWPSEL | STM32_FDCANSEL | STM32_DFSDM1SEL |
+ STM32_SPDIFSEL | STM32_SPDIFSEL | STM32_SPI45SEL |
+ STM32_SPI123SEL | STM32_SAI1SEL
+#if !defined(STM32H723xx)
+ | STM32_SAI23SEL
+#endif
+ ;
+ RCC->D2CCIP2R = STM32_LPTIM1SEL | STM32_CECSEL | STM32_USBSEL |
+ STM32_RNGSEL | STM32_USART234578SEL
+#if !defined(STM32H723xx)
+ | STM32_USART16SEL | STM32_I2C123SEL;
+#else
+ | STM32_USART16910SEL | STM32_I2C1235SEL;
+#endif
+ RCC->D3CCIPR = STM32_SPI6SEL | STM32_SAI4BSEL | STM32_SAI4ASEL |
+ STM32_ADCSEL | STM32_LPTIM345SEL | STM32_LPTIM2SEL |
+ STM32_I2C4SEL | STM32_LPUART1SEL;
+
+ /* Flash setup.*/
+ FLASH->ACR = FLASH_ACR_WRHIGHFREQ_1 | FLASH_ACR_WRHIGHFREQ_0 |
+ STM32_FLASHBITS;
+ while ((FLASH->ACR & FLASH_ACR_LATENCY) !=
+ (STM32_FLASHBITS & FLASH_ACR_LATENCY)) {
+ }
+
+ /* Switching to the configured clock source if it is different
+ from HSI.*/
+#if STM32_SW != STM32_SW_HSI_CK
+ RCC->CFGR |= STM32_SW; /* Switches on the selected clock source. */
+ while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 3U))
+ ;
+#endif
+
+#if 0
+ /* Peripheral clock sources.*/
+ RCC->DCKCFGR2 = STM32_SDMMCSEL | STM32_CK48MSEL | STM32_CECSEL |
+ STM32_LPTIM1SEL | STM32_I2C4SEL | STM32_I2C3SEL |
+ STM32_I2C2SEL | STM32_I2C1SEL | STM32_UART8SEL |
+ STM32_UART7SEL | STM32_USART6SEL | STM32_UART5SEL |
+ STM32_UART4SEL | STM32_USART3SEL | STM32_USART2SEL |
+ STM32_USART1SEL;
+#endif
+
+ /* RAM1 2 and 3 clocks enabled.*/
+ rccEnableSRAM1(true);
+ rccEnableSRAM2(true);
+#if !defined(STM32H723xx)
+ rccEnableSRAM3(true);
+#endif
+#endif /* STM32_NO_INIT */
+}
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h new file mode 100644 index 0000000..b1b9a42 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/hal_lld.h @@ -0,0 +1,3199 @@ +/*
+ 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 STM32H7xx/hal_lld.h
+ * @brief STM32H7xx HAL subsystem low level driver header.
+ * @pre This module requires the following macros to be defined in the
+ * @p board.h file:
+ * - STM32_LSECLK.
+ * - STM32_LSEDRV.
+ * - STM32_LSE_BYPASS (optionally).
+ * - STM32_HSECLK.
+ * - STM32_HSE_BYPASS (optionally).
+ * - STM32_VDD (as hundredths of Volt).
+ * .
+ * One of the following macros must also be defined:
+ * - STM32H743xx, STM32H753xx very high-performance MCUs.
+ * .
+ *
+ * @addtogroup HAL
+ * @{
+ */
+
+#ifndef HAL_LLD_H
+#define HAL_LLD_H
+
+#include "stm32_registry.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Platform identification macros
+ * @{
+ */
+#if defined(STM32H723xx) || defined(__DOXYGEN__)
+#define PLATFORM_NAME "STM32H723 Single Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H742xx) || defined(__DOXYGEN__)
+#define PLATFORM_NAME "STM32H742 Single Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H743xx) || defined(__DOXYGEN__)
+#define PLATFORM_NAME "STM32H743 Single Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H753xx)
+#define PLATFORM_NAME "STM32H753 Single Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H745xx) || defined(__DOXYGEN__)
+#define PLATFORM_NAME "STM32H745 Dual Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H755xx)
+#define PLATFORM_NAME "STM32H755 Dual Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H747xx) || defined(__DOXYGEN__)
+#define PLATFORM_NAME "STM32H747 Dual Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H757xx)
+#define PLATFORM_NAME "STM32H757 Dual Core Very High Performance with DSP and FPU"
+
+#elif defined(STM32H750xx)
+#define PLATFORM_NAME "STM32H750 Value Line Very High Performance with DSP and FPU"
+
+#else
+#error "STM32H7xx device not specified"
+#endif
+/** @} */
+
+/**
+ * @name Sub-family identifier
+ */
+#if !defined(STM32H7XX) || defined(__DOXYGEN__)
+#define STM32H7XX
+#endif
+/** @} */
+
+#if !defined(STM32_ENFORCE_H7_REV_XY)
+/**
+ * @name Absolute Maximum Ratings
+ * @{
+ */
+
+#if !defined(STM32H723xx)
+
+/**
+ * @brief Absolute maximum system clock.
+ */
+#define STM32_SYSCLK_MAX 480000000
+
+/**
+ * @brief Maximum SYSCLK clock frequency without voltage boost.
+ */
+#define STM32_SYSCLK_MAX_NOBOOST 400000000
+
+#else // then defined(STM32H723xx)
+
+/**
+ * @brief Absolute maximum system clock.
+ */
+#define STM32_SYSCLK_MAX 550000000
+
+/**
+ * @brief Maximum SYSCLK clock frequency without voltage boost.
+ */
+#define STM32_SYSCLK_MAX_NOBOOST 550000000
+
+#endif // !defined(STM32H723xx)
+
+/**
+ * @brief Absolute maximum HCLK clock.
+ */
+#define STM32_HCLK_MAX (STM32_SYSCLK_MAX / 2)
+
+/**
+ * @brief Maximum HSE clock frequency.
+ */
+#define STM32_HSECLK_MAX 48000000
+
+/**
+ * @brief Maximum HSE clock frequency using an external source.
+ */
+#define STM32_HSECLK_BYP_MAX 50000000
+
+/**
+ * @brief Minimum HSE clock frequency.
+ */
+#define STM32_HSECLK_MIN 4000000
+
+/**
+ * @brief Minimum HSE clock frequency.
+ */
+#define STM32_HSECLK_BYP_MIN 4000000
+
+/**
+ * @brief Maximum LSE clock frequency.
+ */
+#define STM32_LSE_CK_MAX 32768
+
+/**
+ * @brief Maximum LSE clock frequency.
+ */
+#define STM32_LSE_CK_BYP_MAX 1000000
+
+/**
+ * @brief Minimum LSE clock frequency.
+ */
+#define STM32_LSE_CK_MIN 32768
+
+/**
+ * @brief Minimum PLLs input clock frequency..
+ */
+#define STM32_PLLIN_MIN 1000000
+
+/**
+ * @brief PLLs input threshold frequency 1.
+ */
+#define STM32_PLLIN_THRESHOLD1 2000000
+
+/**
+ * @brief PLLs input threshold frequency 2.
+ */
+#define STM32_PLLIN_THRESHOLD2 4000000
+
+/**
+ * @brief PLLs input threshold frequency 3.
+ */
+#define STM32_PLLIN_THRESHOLD3 8000000
+
+/**
+ * @brief Maximum PLLs input clock frequency.
+ */
+#define STM32_PLLIN_MAX 16000000
+
+/**
+ * @brief Minimum PLLs VCO clock frequency.
+ */
+#define STM32_PLLVCO_MIN 150000000 /* DS says 192, RM says 150. */
+
+/**
+ * @brief Threshold PLLs clock frequency.
+ */
+#define STM32_PLLVCO_THRESHOLD 420000000
+
+/**
+ * @brief Maximum PLLs VCOH clock frequency.
+ */
+#define STM32_PLLVCO_MAX 960000000
+
+/**
+ * @brief Maximum APB1 clock frequency.
+ */
+#define STM32_PCLK1_MAX (STM32_HCLK_MAX / 2)
+
+/**
+ * @brief Maximum APB2 clock frequency.
+ */
+#define STM32_PCLK2_MAX (STM32_HCLK_MAX / 2)
+
+/**
+ * @brief Maximum APB3 clock frequency.
+ */
+#define STM32_PCLK3_MAX (STM32_HCLK_MAX / 2)
+
+/**
+ * @brief Maximum APB4 clock frequency.
+ */
+#define STM32_PCLK4_MAX (STM32_HCLK_MAX / 2)
+
+/**
+ * @brief Maximum SPI1, SPI2 and SPI3 clock frequency.
+ */
+#define STM32_SPI123_MAX 200000000
+
+/**
+ * @brief Maximum SPI4, SPI5 and SPI6 clock frequency.
+ */
+#define STM32_SPI456_MAX 125000000
+
+/**
+ * @brief Maximum ADC clock frequency.
+ */
+#define STM32_ADCCLK_MAX 50000000
+/** @} */
+
+#else /* defined(STM32_ENFORCE_H7_REV_XY) */
+
+#define STM32_SYSCLK_MAX 400000000
+#define STM32_SYSCLK_MAX_NOBOOST 400000000
+#define STM32_HCLK_MAX (STM32_SYSCLK_MAX / 2)
+#define STM32_HSECLK_MAX 48000000
+#define STM32_HSECLK_BYP_MAX 50000000
+#define STM32_HSECLK_MIN 4000000
+#define STM32_HSECLK_BYP_MIN 4000000
+#define STM32_LSE_CK_MAX 32768
+#define STM32_LSE_CK_BYP_MAX 1000000
+#define STM32_LSE_CK_MIN 32768
+#define STM32_PLLIN_MIN 1000000
+#define STM32_PLLIN_THRESHOLD1 2000000
+#define STM32_PLLIN_THRESHOLD2 4000000
+#define STM32_PLLIN_THRESHOLD3 8000000
+#define STM32_PLLIN_MAX 16000000
+#define STM32_PLLVCO_MIN 150000000
+#define STM32_PLLVCO_THRESHOLD 420000000
+#define STM32_PLLVCO_MAX 836000000
+#define STM32_PCLK1_MAX (STM32_HCLK_MAX / 2)
+#define STM32_PCLK2_MAX (STM32_HCLK_MAX / 2)
+#define STM32_PCLK3_MAX (STM32_HCLK_MAX / 2)
+#define STM32_PCLK4_MAX (STM32_HCLK_MAX / 2)
+#define STM32_SPI123_MAX 133000000
+#define STM32_SPI456_MAX 100000000
+#define STM32_ADCCLK_MAX 36000000
+
+#endif /* defined(STM32_ENFORCE_H7_REV_XY) */
+
+/**
+ * @name Internal clock sources frequencies
+ * @{
+ */
+#define STM32_HSI_OSC 64000000
+#define STM32_HSI48_OSC 48000000
+#define STM32_CSI_OSC 4000000
+#define STM32_LSI_OSC 32000
+/** @} */
+
+/**
+ * @name Register helpers not found in ST headers
+ * @{
+ */
+#define RCC_CR_HSIDIV_VALUE(n) ((n) << 3U)
+
+#define RCC_CFGR_SW_VALUE(n) ((n) << 0U)
+#define RCC_CFGR_RTCPRE_VALUE(n) ((n) << 8U)
+#define RCC_CFGR_MCO1PRE_VALUE(n) ((n) << 18U)
+#define RCC_CFGR_MCO1_VALUE(n) ((n) << 22U)
+#define RCC_CFGR_MCO2PRE_VALUE(n) ((n) << 25U)
+#define RCC_CFGR_MCO2_VALUE(n) ((n) << 29U)
+
+#define RCC_D1CFGR_D1HPRE_VALUE(n) ((n) << RCC_D1CFGR_HPRE_Pos)
+#define RCC_D1CFGR_D1CPRE_VALUE(n) ((n) << RCC_D1CFGR_D1CPRE_Pos)
+#define RCC_D1CFGR_D1PPRE3_VALUE(n) ((n) << RCC_D1CFGR_D1PPRE_Pos)
+
+#define RCC_D2CFGR_D2PPRE1_VALUE(n) ((n) << RCC_D2CFGR_D2PPRE1_Pos)
+#define RCC_D2CFGR_D2PPRE2_VALUE(n) ((n) << RCC_D2CFGR_D2PPRE2_Pos)
+
+#define RCC_D3CFGR_D3PPRE4_VALUE(n) ((n) << RCC_D3CFGR_D3PPRE_Pos)
+
+#define RCC_PLLCKSELR_PLLSRC_VALUE(n) ((n) << RCC_PLLCKSELR_PLLSRC_Pos)
+
+#define RCC_PLLCKSELR_DIVM1_VALUE(n) ((n) << RCC_PLLCKSELR_DIVM1_Pos)
+#define RCC_PLLCKSELR_DIVM2_VALUE(n) ((n) << RCC_PLLCKSELR_DIVM2_Pos)
+#define RCC_PLLCKSELR_DIVM3_VALUE(n) ((n) << RCC_PLLCKSELR_DIVM3_Pos)
+
+#define RCC_PLL1DIVR_DIVN1_VALUE(n) ((n) << RCC_PLL1DIVR_N1)
+#define RCC_PLL1DIVR_DIVP1_VALUE(n) ((n) << RCC_PLL1DIVR_P1)
+#define RCC_PLL1DIVR_DIVQ1_VALUE(n) ((n) << RCC_PLL1DIVR_Q1)
+#define RCC_PLL1DIVR_DIVR1_VALUE(n) ((n) << RCC_PLL1DIVR_R1)
+
+#define RCC_PLL1FRACR_FRACN1_VALUE(n) ((n) << RCC_PLL1FRACR_FRACN1_Pos)
+
+#define RCC_PLL2DIVR_DIVN2_VALUE(n) ((n) << RCC_PLL2DIVR_N2)
+#define RCC_PLL2DIVR_DIVP2_VALUE(n) ((n) << RCC_PLL2DIVR_P2)
+#define RCC_PLL2DIVR_DIVQ2_VALUE(n) ((n) << RCC_PLL2DIVR_Q2)
+#define RCC_PLL2DIVR_DIVR2_VALUE(n) ((n) << RCC_PLL2DIVR_R2)
+
+#define RCC_PLL2FRACR_FRACN2_VALUE(n) ((n) << RCC_PLL2FRACR_FRACN2_Pos)
+
+#define RCC_PLL3DIVR_DIVN3_VALUE(n) ((n) << RCC_PLL3DIVR_N3)
+#define RCC_PLL3DIVR_DIVP3_VALUE(n) ((n) << RCC_PLL3DIVR_P3)
+#define RCC_PLL3DIVR_DIVQ3_VALUE(n) ((n) << RCC_PLL3DIVR_Q3)
+#define RCC_PLL3DIVR_DIVR3_VALUE(n) ((n) << RCC_PLL3DIVR_R3)
+
+#define RCC_PLL3FRACR_FRACN3_VALUE(n) ((n) << RCC_PLL3FRACR_FRACN3_Pos)
+
+#define RCC_D1CCIPR_CKPERSEL_VALUE(n) ((n) << RCC_D1CCIPR_CKPERSEL_Pos)
+#define RCC_D1CCIPR_SDMMCSEL_VALUE(n) ((n) << RCC_D1CCIPR_SDMMCSEL_Pos)
+#if !defined(STM32H723xx)
+#define RCC_D1CCIPR_QSPISEL_VALUE(n) ((n) << RCC_D1CCIPR_QSPISEL_Pos)
+#endif
+#define RCC_D1CCIPR_FMCSEL_VALUE(n) ((n) << RCC_D1CCIPR_FMCSEL_Pos)
+
+#define RCC_D2CCIP1R_SWPSEL_VALUE(n) ((n) << RCC_D2CCIP1R_SWPSEL_Pos)
+#define RCC_D2CCIP1R_FDCANSEL_VALUE(n) ((n) << RCC_D2CCIP1R_FDCANSEL_Pos)
+#define RCC_D2CCIP1R_DFSDM1SEL_VALUE(n) ((n) << RCC_D2CCIP1R_DFSDM1SEL_Pos)
+#define RCC_D2CCIP1R_SPDIFSEL_VALUE(n) ((n) << RCC_D2CCIP1R_SPDIFSEL_Pos)
+#define RCC_D2CCIP1R_SPI45SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SPI45SEL_Pos)
+#define RCC_D2CCIP1R_SPI123SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SPI123SEL_Pos)
+#if !defined(STM32H723xx)
+#define RCC_D2CCIP1R_SAI23SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SAI23SEL_Pos)
+#endif
+#define RCC_D2CCIP1R_SAI1SEL_VALUE(n) ((n) << RCC_D2CCIP1R_SAI1SEL_Pos)
+
+#define RCC_D2CCIP2R_LPTIM1SEL_VALUE(n) ((n) << RCC_D2CCIP2R_LPTIM1SEL_Pos)
+#define RCC_D2CCIP2R_CECSEL_VALUE(n) ((n) << RCC_D2CCIP2R_CECSEL_Pos)
+#define RCC_D2CCIP2R_USBSEL_VALUE(n) ((n) << RCC_D2CCIP2R_USBSEL_Pos)
+#if !defined(STM32H723xx)
+#define RCC_D2CCIP2R_I2C123SEL_VALUE(n) ((n) << RCC_D2CCIP2R_I2C123SEL_Pos)
+#else
+#define RCC_D2CCIP2R_I2C1235SEL_VALUE(n) ((n) << RCC_D2CCIP2R_I2C1235SEL_Pos)
+#endif
+#define RCC_D2CCIP2R_RNGSEL_VALUE(n) ((n) << RCC_D2CCIP2R_RNGSEL_Pos)
+#if !defined(STM32H723xx)
+#define RCC_D2CCIP2R_USART16SEL_VALUE(n) ((n) << RCC_D2CCIP2R_USART16SEL_Pos)
+#else
+#define RCC_D2CCIP2R_USART16910SEL_VALUE(n) ((n) << RCC_D2CCIP2R_USART16910SEL_Pos)
+#endif
+#define RCC_D2CCIP2R_USART234578SEL_VALUE(n) ((n) << RCC_D2CCIP2R_USART28SEL_Pos)
+
+#define RCC_D3CCIPR_SPI6SEL_VALUE(n) ((n) << RCC_D3CCIPR_SPI6SEL_Pos)
+#define RCC_D3CCIPR_SAI4BSEL_VALUE(n) ((n) << RCC_D3CCIPR_SAI4BSEL_Pos)
+#define RCC_D3CCIPR_SAI4ASEL_VALUE(n) ((n) << RCC_D3CCIPR_SAI4ASEL_Pos)
+#define RCC_D3CCIPR_ADCSEL_VALUE(n) ((n) << RCC_D3CCIPR_ADCSEL_Pos)
+#define RCC_D3CCIPR_LPTIM345SEL_VALUE(n) ((n) << RCC_D3CCIPR_LPTIM345SEL_Pos)
+#define RCC_D3CCIPR_LPTIM2SEL_VALUE(n) ((n) << RCC_D3CCIPR_LPTIM2SEL_Pos)
+#define RCC_D3CCIPR_I2C4SEL_VALUE(n) ((n) << RCC_D3CCIPR_I2C4SEL_Pos)
+#define RCC_D3CCIPR_LPUART1SEL_VALUE(n) ((n) << RCC_D3CCIPR_LPUART1SEL_Pos)
+
+#define RCC_BDCR_RTCSEL_VALUE(n) ((n) << RCC_BDCR_RTCSEL_Pos)
+/** @} */
+
+/**
+ * @name Configuration switches to be used in @p mcuconf.h
+ * @{
+ */
+#define STM32_ODEN_DISABLED 0U
+#define STM32_ODEN_ENABLED (SYSCFG_PWRCR_ODEN)
+
+#define STM32_VOS_SCALE3 (PWR_D3CR_VOS_0)
+#define STM32_VOS_SCALE2 (PWR_D3CR_VOS_1)
+#define STM32_VOS_SCALE1 (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0)
+
+#define STM32_SW_HSI_CK RCC_CFGR_SW_VALUE(0U)
+#define STM32_SW_CSI_CK RCC_CFGR_SW_VALUE(1U)
+#define STM32_SW_HSE_CK RCC_CFGR_SW_VALUE(2U)
+#define STM32_SW_PLL1_P_CK RCC_CFGR_SW_VALUE(3U)
+
+#define STM32_D1CPRE_DIV1 RCC_D1CFGR_D1CPRE_VALUE(0U)
+#define STM32_D1CPRE_DIV2 RCC_D1CFGR_D1CPRE_VALUE(8U)
+#define STM32_D1CPRE_DIV4 RCC_D1CFGR_D1CPRE_VALUE(9U)
+#define STM32_D1CPRE_DIV8 RCC_D1CFGR_D1CPRE_VALUE(10U)
+#define STM32_D1CPRE_DIV16 RCC_D1CFGR_D1CPRE_VALUE(11U)
+#define STM32_D1CPRE_DIV64 RCC_D1CFGR_D1CPRE_VALUE(12U)
+#define STM32_D1CPRE_DIV128 RCC_D1CFGR_D1CPRE_VALUE(13U)
+#define STM32_D1CPRE_DIV256 RCC_D1CFGR_D1CPRE_VALUE(14U)
+#define STM32_D1CPRE_DIV512 RCC_D1CFGR_D1CPRE_VALUE(15U)
+
+#define STM32_D1HPRE_DIV1 RCC_D1CFGR_D1HPRE_VALUE(0U)
+#define STM32_D1HPRE_DIV2 RCC_D1CFGR_D1HPRE_VALUE(8U)
+#define STM32_D1HPRE_DIV4 RCC_D1CFGR_D1HPRE_VALUE(9U)
+#define STM32_D1HPRE_DIV8 RCC_D1CFGR_D1HPRE_VALUE(10U)
+#define STM32_D1HPRE_DIV16 RCC_D1CFGR_D1HPRE_VALUE(11U)
+#define STM32_D1HPRE_DIV64 RCC_D1CFGR_D1HPRE_VALUE(12U)
+#define STM32_D1HPRE_DIV128 RCC_D1CFGR_D1HPRE_VALUE(13U)
+#define STM32_D1HPRE_DIV256 RCC_D1CFGR_D1HPRE_VALUE(14U)
+#define STM32_D1HPRE_DIV512 RCC_D1CFGR_D1HPRE_VALUE(15U)
+
+#define STM32_D1PPRE3_DIV1 RCC_D1CFGR_D1PPRE3_VALUE(0U)
+#define STM32_D1PPRE3_DIV2 RCC_D1CFGR_D1PPRE3_VALUE(4U)
+#define STM32_D1PPRE3_DIV4 RCC_D1CFGR_D1PPRE3_VALUE(5U)
+#define STM32_D1PPRE3_DIV8 RCC_D1CFGR_D1PPRE3_VALUE(6U)
+#define STM32_D1PPRE3_DIV16 RCC_D1CFGR_D1PPRE3_VALUE(7U)
+
+#define STM32_D2PPRE1_DIV1 RCC_D2CFGR_D2PPRE1_VALUE(0U)
+#define STM32_D2PPRE1_DIV2 RCC_D2CFGR_D2PPRE1_VALUE(4U)
+#define STM32_D2PPRE1_DIV4 RCC_D2CFGR_D2PPRE1_VALUE(5U)
+#define STM32_D2PPRE1_DIV8 RCC_D2CFGR_D2PPRE1_VALUE(6U)
+#define STM32_D2PPRE1_DIV16 RCC_D2CFGR_D2PPRE1_VALUE(7U)
+
+#define STM32_D2PPRE2_DIV1 RCC_D2CFGR_D2PPRE2_VALUE(0U)
+#define STM32_D2PPRE2_DIV2 RCC_D2CFGR_D2PPRE2_VALUE(4U)
+#define STM32_D2PPRE2_DIV4 RCC_D2CFGR_D2PPRE2_VALUE(5U)
+#define STM32_D2PPRE2_DIV8 RCC_D2CFGR_D2PPRE2_VALUE(6U)
+#define STM32_D2PPRE2_DIV16 RCC_D2CFGR_D2PPRE2_VALUE(7U)
+
+#define STM32_D3PPRE4_DIV1 RCC_D3CFGR_D3PPRE4_VALUE(0U)
+#define STM32_D3PPRE4_DIV2 RCC_D3CFGR_D3PPRE4_VALUE(4U)
+#define STM32_D3PPRE4_DIV4 RCC_D3CFGR_D3PPRE4_VALUE(5U)
+#define STM32_D3PPRE4_DIV8 RCC_D3CFGR_D3PPRE4_VALUE(6U)
+#define STM32_D3PPRE4_DIV16 RCC_D3CFGR_D3PPRE4_VALUE(7U)
+
+#define STM32_HSIDIV_DIV1 RCC_CR_HSIDIV_VALUE(0U)
+#define STM32_HSIDIV_DIV2 RCC_CR_HSIDIV_VALUE(1U)
+#define STM32_HSIDIV_DIV4 RCC_CR_HSIDIV_VALUE(2U)
+#define STM32_HSIDIV_DIV8 RCC_CR_HSIDIV_VALUE(3U)
+
+#define STM32_MCO1SEL_HSI_CK RCC_CFGR_MCO1_VALUE(0U)
+#define STM32_MCO1SEL_LSE_CK RCC_CFGR_MCO1_VALUE(1U)
+#define STM32_MCO1SEL_HSE_CK RCC_CFGR_MCO1_VALUE(2U)
+#define STM32_MCO1SEL_PLL1_Q_CK RCC_CFGR_MCO1_VALUE(3U)
+#define STM32_MCO1SEL_HSI48_CK RCC_CFGR_MCO1_VALUE(4U)
+
+#define STM32_MCO2SEL_SYS_CK RCC_CFGR_MCO2_VALUE(0U)
+#define STM32_MCO2SEL_PLL2_P_CK RCC_CFGR_MCO2_VALUE(1U)
+#define STM32_MCO2SEL_HSE_CK RCC_CFGR_MCO2_VALUE(2U)
+#define STM32_MCO2SEL_PLL1_P_CK RCC_CFGR_MCO2_VALUE(3U)
+#define STM32_MCO2SEL_CSI_CK RCC_CFGR_MCO2_VALUE(4U)
+#define STM32_MCO2SEL_LSI_CK RCC_CFGR_MCO2_VALUE(5U)
+
+#define STM32_RTCSEL_MASK RCC_BDCR_RTCSEL_Msk
+#define STM32_RTCSEL_NOCLK RCC_BDCR_RTCSEL_VALUE(0U)
+#define STM32_RTCSEL_LSE_CK RCC_BDCR_RTCSEL_VALUE(1U)
+#define STM32_RTCSEL_LSI_CK RCC_BDCR_RTCSEL_VALUE(2U)
+#define STM32_RTCSEL_HSE_1M_CK RCC_BDCR_RTCSEL_VALUE(3U)
+
+#define STM32_HRTIMSEL_C_CLK RCC_CFGR_HRTIMSEL
+
+#define STM32_STOPKERWUCK_ENABLED RCC_CFGR_STOPKERWUCK
+
+#define STM32_STOPWUCK_ENABLED RCC_CFGR_STOPKERWUCK
+
+#define STM32_PLLSRC_HSI_CK RCC_PLLCKSELR_PLLSRC_VALUE(0U)
+#define STM32_PLLSRC_CSI_CK RCC_PLLCKSELR_PLLSRC_VALUE(1U)
+#define STM32_PLLSRC_HSE_CK RCC_PLLCKSELR_PLLSRC_VALUE(2U)
+#define STM32_PLLSRC_DISABLE RCC_PLLCKSELR_PLLSRC_VALUE(23U)
+
+#define STM32_CKPERSEL_HSI_CK RCC_D1CCIPR_CKPERSEL_VALUE(0U)
+#define STM32_CKPERSEL_CSI_CK RCC_D1CCIPR_CKPERSEL_VALUE(1U)
+#define STM32_CKPERSEL_HSE_CK RCC_D1CCIPR_CKPERSEL_VALUE(2U)
+
+#define STM32_SDMMCSEL_PLL1_Q_CK RCC_D1CCIPR_SDMMCSEL_VALUE(0U)
+#define STM32_SDMMCSEL_PLL2_R_CK RCC_D1CCIPR_SDMMCSEL_VALUE(1U)
+
+#if !defined(STM32H723xx)
+#define STM32_QSPISEL_HCLK RCC_D1CCIPR_QSPISEL_VALUE(0U)
+#define STM32_QSPISEL_PLL1_Q_CK RCC_D1CCIPR_QSPISEL_VALUE(1U)
+#define STM32_QSPISEL_PLL2_R_CK RCC_D1CCIPR_QSPISEL_VALUE(2U)
+#define STM32_QSPISEL_PER_CK RCC_D1CCIPR_QSPISEL_VALUE(3U)
+#endif
+
+#define STM32_FMCSEL_HCLK RCC_D1CCIPR_FMCSEL_VALUE(0U)
+#define STM32_FMCSEL_PLL1_Q_CK RCC_D1CCIPR_FMCSEL_VALUE(1U)
+#define STM32_FMCSEL_PLL2_R_CK RCC_D1CCIPR_FMCSEL_VALUE(2U)
+#define STM32_FMCSEL_PER_CK RCC_D1CCIPR_FMCSEL_VALUE(3U)
+
+#define STM32_SWPSEL_PCLK1 RCC_D2CCIP1R_SWPSEL_VALUE(0U)
+#define STM32_SWPSEL_HSI_KER_CK RCC_D2CCIP1R_SWPSEL_VALUE(1U)
+
+#define STM32_FDCANSEL_HSE_CK RCC_D2CCIP1R_FDCANSEL_VALUE(0U)
+#define STM32_FDCANSEL_PLL1_Q_CK RCC_D2CCIP1R_FDCANSEL_VALUE(1U)
+#define STM32_FDCANSEL_PLL2_Q_CK RCC_D2CCIP1R_FDCANSEL_VALUE(2U)
+
+#define STM32_DFSDM1SEL_PCLK2 RCC_D2CCIP1R_DFSDM1SEL_VALUE(0U)
+#define STM32_DFSDM1SEL_SYS_CK RCC_D2CCIP1R_DFSDM1SEL_VALUE(1U)
+
+#define STM32_SPDIFSEL_PLL1_Q_CK RCC_D2CCIP1R_SPDIFSEL_VALUE(0U)
+#define STM32_SPDIFSEL_PLL2_R_CK RCC_D2CCIP1R_SPDIFSEL_VALUE(1U)
+#define STM32_SPDIFSEL_PLL3_R_CK RCC_D2CCIP1R_SPDIFSEL_VALUE(2U)
+#define STM32_SPDIFSEL_HSI_KET_CLK RCC_D2CCIP1R_SPDIFSEL_VALUE(3U)
+
+#define STM32_SPI45SEL_PCLK2 RCC_D2CCIP1R_SPI45SEL_VALUE(0U)
+#define STM32_SPI45SEL_PLL2_Q_CK RCC_D2CCIP1R_SPI45SEL_VALUE(1U)
+#define STM32_SPI45SEL_PLL3_Q_CK RCC_D2CCIP1R_SPI45SEL_VALUE(2U)
+#define STM32_SPI45SEL_HSI_KER_CK RCC_D2CCIP1R_SPI45SEL_VALUE(3U)
+#define STM32_SPI45SEL_CSI_KER_CK RCC_D2CCIP1R_SPI45SEL_VALUE(4U)
+#define STM32_SPI45SEL_HSE_CK RCC_D2CCIP1R_SPI45SEL_VALUE(5U)
+
+#define STM32_SPI123SEL_PLL1_Q_CK RCC_D2CCIP1R_SPI123SEL_VALUE(0U)
+#define STM32_SPI123SEL_PLL2_P_CK RCC_D2CCIP1R_SPI123SEL_VALUE(1U)
+#define STM32_SPI123SEL_PLL3_P_CK RCC_D2CCIP1R_SPI123SEL_VALUE(2U)
+#define STM32_SPI123SEL_I2S_CKIN RCC_D2CCIP1R_SPI123SEL_VALUE(3U)
+#define STM32_SPI123SEL_PER_CK RCC_D2CCIP1R_SPI123SEL_VALUE(4U)
+
+#if !defined(STM32H723xx)
+#define STM32_SAI23SEL_PLL1_Q_CK RCC_D2CCIP1R_SAI23SEL_VALUE(0U)
+#define STM32_SAI23SEL_PLL2_P_CK RCC_D2CCIP1R_SAI23SEL_VALUE(1U)
+#define STM32_SAI23SEL_PLL3_P_CK RCC_D2CCIP1R_SAI23SEL_VALUE(2U)
+#define STM32_SAI23SEL_I2S_CKIN RCC_D2CCIP1R_SAI23SEL_VALUE(3U)
+#define STM32_SAI23SEL_PER_CK RCC_D2CCIP1R_SAI23SEL_VALUE(4U)
+#endif
+
+#define STM32_SAI1SEL_PLL1_Q_CK RCC_D2CCIP1R_SAI1SEL_VALUE(0U)
+#define STM32_SAI1SEL_PLL2_P_CK RCC_D2CCIP1R_SAI1SEL_VALUE(1U)
+#define STM32_SAI1SEL_PLL3_P_CK RCC_D2CCIP1R_SAI1SEL_VALUE(2U)
+#define STM32_SAI1SEL_I2S_CKIN RCC_D2CCIP1R_SAI1SEL_VALUE(3U)
+#define STM32_SAI1SEL_PER_CK RCC_D2CCIP1R_SAI1SEL_VALUE(4U)
+
+#define STM32_LPTIM1SEL_PCLK1 RCC_D2CCIP2R_LPTIM1SEL_VALUE(0U)
+#define STM32_LPTIM1SEL_PLL2_P_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(1U)
+#define STM32_LPTIM1SEL_PLL3_R_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(2U)
+#define STM32_LPTIM1SEL_LSE_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(3U)
+#define STM32_LPTIM1SEL_LSI_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(4U)
+#define STM32_LPTIM1SEL_PER_CK RCC_D2CCIP2R_LPTIM1SEL_VALUE(5U)
+
+#define STM32_CECSEL_LSE_CK RCC_D2CCIP2R_CECSEL_VALUE(0U)
+#define STM32_CECSEL_LSI_CK RCC_D2CCIP2R_CECSEL_VALUE(1U)
+#define STM32_CECSEL_CSI_KER_CK RCC_D2CCIP2R_CECSEL_VALUE(2U)
+#define STM32_CECSEL_DISABLE RCC_D2CCIP2R_CECSEL_VALUE(3U)
+
+#define STM32_USBSEL_DISABLE RCC_D2CCIP2R_USBSEL_VALUE(0U)
+#define STM32_USBSEL_PLL1_Q_CK RCC_D2CCIP2R_USBSEL_VALUE(1U)
+#define STM32_USBSEL_PLL3_Q_CK RCC_D2CCIP2R_USBSEL_VALUE(2U)
+#define STM32_USBSEL_HSI48_CK RCC_D2CCIP2R_USBSEL_VALUE(3U)
+
+#define STM32_I2C1235SEL_PCLK1 RCC_D2CCIP2R_I2C1235SEL_VALUE(0U)
+#define STM32_I2C1235SEL_PLL3_R_CK RCC_D2CCIP2R_I2C1235SEL_VALUE(1U)
+#define STM32_I2C1235SEL_HSI_KER_CK RCC_D2CCIP2R_I2C1235SEL_VALUE(2U)
+#define STM32_I2C1235SEL_CSI_KER_CK RCC_D2CCIP2R_I2C1235SEL_VALUE(3U)
+
+#define STM32_RNGSEL_HSI48_CK RCC_D2CCIP2R_RNGSEL_VALUE(0U)
+#define STM32_RNGSEL_PLL1_Q_CK RCC_D2CCIP2R_RNGSEL_VALUE(1U)
+#define STM32_RNGSEL_LSE_CK RCC_D2CCIP2R_RNGSEL_VALUE(2U)
+#define STM32_RNGSEL_LSI_CK RCC_D2CCIP2R_RNGSEL_VALUE(3U)
+
+#if !defined(STM32H723xx)
+#define STM32_USART16SEL_PCLK2 RCC_D2CCIP2R_USART16SEL_VALUE(0U)
+#define STM32_USART16SEL_PLL2_Q_CK RCC_D2CCIP2R_USART16SEL_VALUE(1U)
+#define STM32_USART16SEL_PLL3_Q_CK RCC_D2CCIP2R_USART16SEL_VALUE(2U)
+#define STM32_USART16SEL_HSI_KER_CK RCC_D2CCIP2R_USART16SEL_VALUE(3U)
+#define STM32_USART16SEL_CSI_KER_CK RCC_D2CCIP2R_USART16SEL_VALUE(4U)
+#define STM32_USART16SEL_LSE_CK RCC_D2CCIP2R_USART16SEL_VALUE(5U)
+#else
+#define STM32_USART16910SEL_PCLK2 RCC_D2CCIP2R_USART16910SEL_VALUE(0U)
+#define STM32_USART16910SEL_PLL2_Q_CK RCC_D2CCIP2R_USART16910SEL_VALUE(1U)
+#define STM32_USART16910SEL_PLL3_Q_CK RCC_D2CCIP2R_USART16910SEL_VALUE(2U)
+#define STM32_USART16910SEL_HSI_KER_CK RCC_D2CCIP2R_USART16910SEL_VALUE(3U)
+#define STM32_USART16910SEL_CSI_KER_CK RCC_D2CCIP2R_USART16910SEL_VALUE(4U)
+#define STM32_USART16910SEL_LSE_CK RCC_D2CCIP2R_USART16910SEL_VALUE(5U)
+#endif
+
+#define STM32_USART234578SEL_PCLK1 RCC_D2CCIP2R_USART234578SEL_VALUE(0U)
+#define STM32_USART234578SEL_PLL2_Q_CK RCC_D2CCIP2R_USART234578SEL_VALUE(1U)
+#define STM32_USART234578SEL_PLL3_Q_CK RCC_D2CCIP2R_USART234578SEL_VALUE(2U)
+#define STM32_USART234578SEL_HSI_KER_CK RCC_D2CCIP2R_USART234578SEL_VALUE(3U)
+#define STM32_USART234578SEL_CSI_KER_CK RCC_D2CCIP2R_USART234578SEL_VALUE(4U)
+#define STM32_USART234578SEL_LSE_CK RCC_D2CCIP2R_USART234578SEL_VALUE(5U)
+
+#define STM32_SPI6SEL_PCLK4 RCC_D3CCIPR_SPI6SEL_VALUE(0U)
+#define STM32_SPI6SEL_PLL2_Q_CK RCC_D3CCIPR_SPI6SEL_VALUE(1U)
+#define STM32_SPI6SEL_PLL3_Q_CK RCC_D3CCIPR_SPI6SEL_VALUE(2U)
+#define STM32_SPI6SEL_HSI_KER_CK RCC_D3CCIPR_SPI6SEL_VALUE(3U)
+#define STM32_SPI6SEL_CSI_KER_CK RCC_D3CCIPR_SPI6SEL_VALUE(4U)
+#define STM32_SPI6SEL_HSE_CK RCC_D3CCIPR_SPI6SEL_VALUE(5U)
+
+#define STM32_SAI4BSEL_PLL1_Q_CK RCC_D3CCIPR_SAI4BSEL_VALUE(0U)
+#define STM32_SAI4BSEL_PLL2_P_CK RCC_D3CCIPR_SAI4BSEL_VALUE(1U)
+#define STM32_SAI4BSEL_PLL3_P_CK RCC_D3CCIPR_SAI4BSEL_VALUE(2U)
+#define STM32_SAI4BSEL_I2S_CKIN RCC_D3CCIPR_SAI4BSEL_VALUE(3U)
+#define STM32_SAI4BSEL_PER_CK RCC_D3CCIPR_SAI4BSEL_VALUE(4U)
+
+#define STM32_SAI4ASEL_PLL1_Q_CK RCC_D3CCIPR_SAI4ASEL_VALUE(0U)
+#define STM32_SAI4ASEL_PLL2_P_CK RCC_D3CCIPR_SAI4ASEL_VALUE(1U)
+#define STM32_SAI4ASEL_PLL3_P_CK RCC_D3CCIPR_SAI4ASEL_VALUE(2U)
+#define STM32_SAI4ASEL_I2S_CKIN RCC_D3CCIPR_SAI4ASEL_VALUE(3U)
+#define STM32_SAI4ASEL_PER_CK RCC_D3CCIPR_SAI4ASEL_VALUE(4U)
+
+#define STM32_ADCSEL_PLL2_P_CK RCC_D3CCIPR_ADCSEL_VALUE(0U)
+#define STM32_ADCSEL_PLL3_R_CK RCC_D3CCIPR_ADCSEL_VALUE(1U)
+#define STM32_ADCSEL_PER_CK RCC_D3CCIPR_ADCSEL_VALUE(2U)
+#define STM32_ADCSEL_DISABLE RCC_D3CCIPR_ADCSEL_VALUE(3U)
+
+#define STM32_LPTIM345SEL_PCLK4 RCC_D3CCIPR_LPTIM345SEL_VALUE(0U)
+#define STM32_LPTIM345SEL_PLL2_P_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(1U)
+#define STM32_LPTIM345SEL_PLL3_P_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(2U)
+#define STM32_LPTIM345SEL_LSE_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(3U)
+#define STM32_LPTIM345SEL_LSI_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(4U)
+#define STM32_LPTIM345SEL_PER_CK RCC_D3CCIPR_LPTIM345SEL_VALUE(5U)
+
+#define STM32_LPTIM2SEL_PCLK4 RCC_D3CCIPR_LPTIM2SEL_VALUE(0U)
+#define STM32_LPTIM2SEL_PLL2_P_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(1U)
+#define STM32_LPTIM2SEL_PLL3_P_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(2U)
+#define STM32_LPTIM2SEL_LSE_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(3U)
+#define STM32_LPTIM2SEL_LSI_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(4U)
+#define STM32_LPTIM2SEL_PER_CK RCC_D3CCIPR_LPTIM2SEL_VALUE(5U)
+
+#define STM32_I2C4SEL_PCLK4 RCC_D3CCIPR_I2C4SEL_VALUE(0U)
+#define STM32_I2C4SEL_PLL3_R_CK RCC_D3CCIPR_I2C4SEL_VALUE(1U)
+#define STM32_I2C4SEL_HSI_KER_CK RCC_D3CCIPR_I2C4SEL_VALUE(2U)
+#define STM32_I2C4SEL_CSI_KER_CK RCC_D3CCIPR_I2C4SEL_VALUE(3U)
+
+#define STM32_LPUART1SEL_PCLK4 RCC_D3CCIPR_LPUART1SEL_VALUE(0U)
+#define STM32_LPUART1SEL_PLL2_Q_CK RCC_D3CCIPR_LPUART1SEL_VALUE(1U)
+#define STM32_LPUART1SEL_PLL3_Q_CK RCC_D3CCIPR_LPUART1SEL_VALUE(2U)
+#define STM32_LPUART1SEL_HSI_KER_CK RCC_D3CCIPR_LPUART1SEL_VALUE(3U)
+#define STM32_LPUART1SEL_CSI_KER_CK RCC_D3CCIPR_LPUART1SEL_VALUE(4U)
+#define STM32_LPUART1SEL_LSE_CK RCC_D3CCIPR_LPUART1SEL_VALUE(5U)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Disables the PWR/RCC initialization in the HAL.
+ * @note All the clock tree constants are calculated but the initialization
+ * is not performed.
+ */
+#if !defined(STM32_NO_INIT) || defined(__DOXYGEN__)
+#define STM32_NO_INIT FALSE
+#endif
+
+/**
+ * @brief Target code for this HAL configuration.
+ * @note Core 1 is the Cortex-M7, core 2 is the Cortex-M4.
+ */
+#if !defined(STM32_TARGET_CORE) || defined(__DOXYGEN__)
+#define STM32_TARGET_CORE 1
+#endif
+
+/**
+ * @brief MPU region to be used for no-cache RAM area.
+ */
+#if !defined(STM32_NOCACHE_MPU_REGION) || defined(__DOXYGEN__)
+#define STM32_NOCACHE_MPU_REGION MPU_REGION_6
+#endif
+
+/**
+ * @brief Add no-cache attribute to SRAM1 and SRAM2.
+ * @note MPU region 7 is used if enabled.
+ */
+#if !defined(STM32_NOCACHE_SRAM1_SRAM2) || defined(__DOXYGEN__)
+#define STM32_NOCACHE_SRAM1_SRAM2 FALSE
+#endif
+
+/**
+ * @brief Add no-cache attribute to SRAM3.
+ * @note MPU region 7 is used if enabled.
+ */
+#if !defined(STM32_NOCACHE_SRAM3) || defined(__DOXYGEN__)
+#define STM32_NOCACHE_SRAM3 TRUE
+#endif
+
+/**
+ * @brief PWR CR1 initializer.
+ */
+#if !defined(STM32_PWR_CR1) || defined(__DOXYGEN__)
+#define STM32_PWR_CR1 (PWR_CR1_SVOS_1 | \
+ PWR_CR1_SVOS_0)
+#endif
+
+/**
+ * @brief PWR CR2 initializer.
+ */
+#if !defined(STM32_PWR_CR2) || defined(__DOXYGEN__)
+#define STM32_PWR_CR2 (PWR_CR2_BREN)
+#endif
+
+/**
+ * @brief PWR CR3 initializer.
+ */
+#if !defined(STM32_PWR_CR3) || defined(__DOXYGEN__)
+#define STM32_PWR_CR3 (PWR_CR3_LDOEN | \
+ PWR_CR3_USBREGEN | \
+ PWR_CR3_USB33DEN)
+#endif
+
+/**
+ * @brief PWR CPUCR initializer.
+ */
+#if !defined(STM32_PWR_CPUCR) || defined(__DOXYGEN__)
+#define STM32_PWR_CPUCR 0
+#endif
+
+/**
+ * @brief VOS setting.
+ */
+#if !defined(STM32_VOS) || defined(__DOXYGEN__)
+#define STM32_VOS STM32_VOS_SCALE1
+#endif
+
+/**
+ * @brief Enables or disables the HSI clock source.
+ */
+#if !defined(STM32_HSI_ENABLED) || defined(__DOXYGEN__)
+#define STM32_HSI_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the LSI clock source.
+ */
+#if !defined(STM32_LSI_ENABLED) || defined(__DOXYGEN__)
+#define STM32_LSI_ENABLED FALSE
+#endif
+
+/**
+ * @brief Enables or disables the LSI clock source.
+ */
+#if !defined(STM32_CSI_ENABLED) || defined(__DOXYGEN__)
+#define STM32_CSI_ENABLED FALSE
+#endif
+
+/**
+ * @brief Enables or disables the HSI48 clock source.
+ */
+#if !defined(STM32_HSI48_ENABLED) || defined(__DOXYGEN__)
+#define STM32_HSI48_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the HSE clock source.
+ */
+#if !defined(STM32_HSE_ENABLED) || defined(__DOXYGEN__)
+#define STM32_HSE_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the LSE clock source.
+ */
+#if !defined(STM32_LSE_ENABLED) || defined(__DOXYGEN__)
+#define STM32_LSE_ENABLED TRUE
+#endif
+
+/**
+ * @brief HSI divider.
+ */
+#if !defined(STM32_HSIDIV) || defined(__DOXYGEN__)
+#define STM32_HSIDIV STM32_HSIDIV_DIV1
+#endif
+
+/**
+ * @brief Clock source for all PLLs.
+ */
+#if !defined(STM32_PLLSRC) || defined(__DOXYGEN__)
+#define STM32_PLLSRC STM32_PLLSRC_HSE_CK
+#endif
+
+/**
+ * @brief Masking of PLLCFGR register.
+ * @note By default all options in PLLCFGR are enabled, this option
+ * allows to mask specific bits for power saving reasons.
+ * Use with caution.
+ */
+#if !defined(STM32_PLLCFGR_MASK) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_MASK ~0
+#endif
+
+/**
+ * @brief Enables or disables the PLL1.
+ */
+#if !defined(STM32_PLL1_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL1_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL1 P output.
+ */
+#if !defined(STM32_PLL1_P_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL1_P_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL1 Q output.
+ */
+#if !defined(STM32_PLL1_Q_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL1_Q_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL1 R output.
+ */
+#if !defined(STM32_PLL1_R_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL1_R_ENABLED TRUE
+#endif
+
+/**
+ * @brief PLL1 DIVM divider.
+ * @note The allowed values are 1..63.
+ */
+#if !defined(STM32_PLL1_DIVM_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL1_DIVM_VALUE 4
+#endif
+
+/**
+ * @brief PLL1 DIVN multiplier.
+ * @note The allowed values are 4..512.
+ */
+#if !defined(STM32_PLL1_DIVN_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL1_DIVN_VALUE 400
+#endif
+
+/**
+ * @brief PLL1 FRACN multiplier, zero if no fractional part.
+ * @note The allowed values are 0..8191.
+ */
+#if !defined(STM32_PLL1_FRACN_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL1_FRACN_VALUE 0
+#endif
+
+/**
+ * @brief PLL1 DIVP divider.
+ * @note The allowed values are 2..128, odd values not allowed.
+ */
+#if !defined(STM32_PLL1_DIVP_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL1_DIVP_VALUE 2
+#endif
+
+/**
+ * @brief PLL1 DIVQ divider.
+ * @note The allowed values are 1..128.
+ */
+#if !defined(STM32_PLL1_DIVQ_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL1_DIVQ_VALUE 8
+#endif
+
+/**
+ * @brief PLL1 DIVR divider.
+ * @note The allowed values are 1..128.
+ */
+#if !defined(STM32_PLL1_DIVR_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL1_DIVR_VALUE 8
+#endif
+
+/**
+ * @brief Enables or disables the PLL2.
+ */
+#if !defined(STM32_PLL2_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL2_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL2 P output.
+ */
+#if !defined(STM32_PLL2_P_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL1_2_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL2 Q output.
+ */
+#if !defined(STM32_PLL2_Q_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL2_Q_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL2 R output.
+ */
+#if !defined(STM32_PLL2_R_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL2_R_ENABLED TRUE
+#endif
+
+/**
+ * @brief PLL2 DIVM divider.
+ * @note The allowed values are 1..63.
+ */
+#if !defined(STM32_PLL2_DIVM_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL2_DIVM_VALUE 4
+#endif
+
+/**
+ * @brief PLL2 DIVN multiplier.
+ * @note The allowed values are 4..512.
+ */
+#if !defined(STM32_PLL2_DIVN_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL2_DIVN_VALUE 400
+#endif
+
+/**
+ * @brief PLL2 FRACN multiplier, zero if no fractional part.
+ * @note The allowed values are 0..8191.
+ */
+#if !defined(STM32_PLL2_FRACN_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL2_FRACN_VALUE 0
+#endif
+
+/**
+ * @brief PLL2 DIVP divider.
+ * @note The allowed values are 2..128, odd values not allowed.
+ */
+#if !defined(STM32_PLL2_DIVP_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL2_DIVP_VALUE 40
+#endif
+
+/**
+ * @brief PLL2 DIVQ divider.
+ * @note The allowed values are 1..128.
+ */
+#if !defined(STM32_PLL2_DIVQ_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL2_DIVQ_VALUE 8
+#endif
+
+/**
+ * @brief PLL2 DIVR divider.
+ * @note The allowed values are 1..128.
+ */
+#if !defined(STM32_PLL2_DIVR_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL2_DIVR_VALUE 8
+#endif
+
+/**
+ * @brief Enables or disables the PLL3.
+ */
+#if !defined(STM32_PLL3_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL3_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL3 P output.
+ */
+#if !defined(STM32_PLL3_P_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL3_P_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL3 Q output.
+ */
+#if !defined(STM32_PLL3_Q_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL3_Q_ENABLED TRUE
+#endif
+
+/**
+ * @brief Enables or disables the PLL3 R output.
+ */
+#if !defined(STM32_PLL3_R_ENABLED) || defined(__DOXYGEN__)
+#define STM32_PLL3_R_ENABLED TRUE
+#endif
+
+/**
+ * @brief PLL3 DIVM divider.
+ * @note The allowed values are 1..63.
+ */
+#if !defined(STM32_PLL3_DIVM_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3_DIVM_VALUE 4
+#endif
+
+/**
+ * @brief PLL3 DIVN multiplier.
+ * @note The allowed values are 4..512.
+ */
+#if !defined(STM32_PLL3_DIVN_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3_DIVN_VALUE 400
+#endif
+
+/**
+ * @brief PLL3 FRACN multiplier, zero if no fractional part.
+ * @note The allowed values are 0..8191.
+ */
+#if !defined(STM32_PLL3_FRACN_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3_FRACN_VALUE 0
+#endif
+
+/**
+ * @brief PLL3 DIVP divider.
+ * @note The allowed values are 2..128, odd values not allowed.
+ */
+#if !defined(STM32_PLL3_DIVP_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3_DIVP_VALUE 8
+#endif
+
+/**
+ * @brief PLL3 DIVQ divider.
+ * @note The allowed values are 1..128.
+ */
+#if !defined(STM32_PLL3_DIVQ_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3_DIVQ_VALUE 8
+#endif
+
+/**
+ * @brief PLL3 DIVR divider.
+ * @note The allowed values are 1..128.
+ */
+#if !defined(STM32_PLL3_DIVR_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3_DIVR_VALUE 8
+#endif
+
+/**
+ * @brief Peripherals clock selector.
+ */
+#if !defined(STM32_CKPERSEL) || defined(__DOXYGEN__)
+#define STM32_CKPERSEL STM32_CKPERSEL_HSE_CK
+#endif
+
+/**
+ * @brief MCO1 clock selector.
+ */
+#if !defined(STM32_MCO1SEL) || defined(__DOXYGEN__)
+#define STM32_MCO1SEL STM32_MCO1SEL_HSI_CK
+#endif
+
+/**
+ * @brief MCO1 clock prescaler.
+ */
+#if !defined(STM32_MCO1PRE_VALUE) || defined(__DOXYGEN__)
+#define STM32_MCO1PRE_VALUE 4
+#endif
+
+/**
+ * @brief MCO2 clock selector.
+ */
+#if !defined(STM32_MCO2SEL) || defined(__DOXYGEN__)
+#define STM32_MCO2SEL STM32_MCO2SEL_SYS_CK
+#endif
+
+/**
+ * @brief MCO2 clock prescaler.
+ */
+#if !defined(STM32_MCO2PRE_VALUE) || defined(__DOXYGEN__)
+#define STM32_MCO2PRE_VALUE 4
+#endif
+
+/**
+ * @brief TIM clock prescaler selection.
+ */
+#if !defined(STM32_TIMPRE_ENABLE) || defined(__DOXYGEN__)
+#define STM32_TIMPRE_ENABLE FALSE
+#endif
+
+/**
+ * @brief HRTIM clock prescaler selection.
+ */
+#if !defined(STM32_HRTIMSEL) || defined(__DOXYGEN__)
+#define STM32_HRTIMSEL 0
+#endif
+
+/**
+ * @brief Kernel clock selection after a wake up from system Stop.
+ */
+#if !defined(STM32_STOPKERWUCK) || defined(__DOXYGEN__)
+#define STM32_STOPKERWUCK 0
+#endif
+
+/**
+ * @brief System clock selection after a wake up from system Stop.
+ */
+#if !defined(STM32_STOPWUCK) || defined(__DOXYGEN__)
+#define STM32_STOPWUCK 0
+#endif
+
+/**
+ * @brief RTC HSE prescaler value.
+ * @note The allowed values are 2..63.
+ */
+#if !defined(STM32_RTCPRE_VALUE) || defined(__DOXYGEN__)
+#define STM32_RTCPRE_VALUE 8
+#endif
+
+/**
+ * @brief Main clock source selection.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_SW) || defined(__DOXYGEN__)
+#define STM32_SW STM32_SW_PLL1_P_CK1_P_CK
+#endif
+
+/**
+ * @brief RTC clock selector.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_RTCSEL) || defined(__DOXYGEN__)
+#define STM32_RTCSEL STM32_RTCSEL_LSE_CK
+#endif
+
+/**
+ * @brief Clock domain 1 core bus prescaler.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_D1CPRE) || defined(__DOXYGEN__)
+#define STM32_D1CPRE STM32_D1CPRE_DIV1
+#endif
+
+/**
+ * @brief Clock domain 1 HPRE prescaler.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_D1HPRE) || defined(__DOXYGEN__)
+#define STM32_D1HPRE STM32_D1HPRE_DIV4
+#endif
+
+/**
+ * @brief Clock domain 1 peripherals bus prescaler.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_D1PPRE3) || defined(__DOXYGEN__)
+#define STM32_D1PPRE3 STM32_D1PPRE3_DIV1
+#endif
+
+/**
+ * @brief Clock domain 2 peripherals bus 1 prescaler.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_D2PPRE1) || defined(__DOXYGEN__)
+#define STM32_D2PPRE1 STM32_D2PPRE1_DIV1
+#endif
+
+/**
+ * @brief Clock domain 2 peripherals bus 2 prescaler.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_D2PPRE2) || defined(__DOXYGEN__)
+#define STM32_D2PPRE2 STM32_D2PPRE2_DIV1
+#endif
+
+/**
+ * @brief Clock domain 3 peripherals bus prescaler.
+ * @note This setting can be modified at runtime.
+ */
+#if !defined(STM32_D3PPRE4) || defined(__DOXYGEN__)
+#define STM32_D3PPRE4 STM32_D3PPRE4_DIV1
+#endif
+
+/**
+ * @brief SDMMC clock source.
+ */
+#if !defined(STM32_SDMMCSEL) || defined(__DOXYGEN__)
+#define STM32_SDMMCSEL STM32_SDMMCSEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief QSPI clock source.
+ */
+#if !defined(STM32H723xx) && (!defined(STM32_QSPISEL) || defined(__DOXYGEN__))
+#define STM32_QSPISEL STM32_QSPISEL_HCLK
+#endif
+
+/**
+ * @brief FMC clock source.
+ */
+#if !defined(STM32H723xx) && (!defined(STM32_FMCSEL) || defined(__DOXYGEN__))
+#define STM32_FMCSEL STM32_QSPISEL_HCLK
+#endif
+
+/**
+ * @brief SWP clock source.
+ */
+#if !defined(STM32_SWPSEL) || defined(__DOXYGEN__)
+#define STM32_SWPSEL STM32_SWPSEL_PCLK1
+#endif
+
+/**
+ * @brief FDCAN clock source.
+ */
+#if !defined(STM32_FDCANSEL) || defined(__DOXYGEN__)
+#define STM32_FDCANSEL STM32_FDCANSEL_HSE_CK
+#endif
+
+/**
+ * @brief DFSDM1 clock source.
+ */
+#if !defined(STM32_DFSDM1SEL) || defined(__DOXYGEN__)
+#define STM32_DFSDM1SEL STM32_DFSDM1SEL_PCLK2
+#endif
+
+/**
+ * @brief SPDIF clock source.
+ */
+#if !defined(STM32_SPDIFSEL) || defined(__DOXYGEN__)
+#define STM32_SPDIFSEL STM32_SPDIFSEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief SPI45 clock source.
+ */
+#if !defined(STM32_SPI45SEL) || defined(__DOXYGEN__)
+#define STM32_SPI45SEL STM32_SPI45SEL_PCLK2
+#endif
+
+/**
+ * @brief SPI123 clock source.
+ */
+#if !defined(STM32_SPI123SEL) || defined(__DOXYGEN__)
+#define STM32_SPI123SEL STM32_SPI123SEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief SAI23 clock source.
+ */
+#if !defined(STM32H723xx) && (!defined(STM32_SAI23SEL) || defined(__DOXYGEN__))
+#define STM32_SAI23SEL STM32_SAI23SEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief SAI1 clock source.
+ */
+#if !defined(STM32_SAI1SEL) || defined(__DOXYGEN__)
+#define STM32_SAI1SEL STM32_SAI1SEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief LPTIM1 clock source.
+ */
+#if !defined(STM32_LPTIM1SEL) || defined(__DOXYGEN__)
+#define STM32_LPTIM1SEL STM32_LPTIM1_PCLK1
+#endif
+
+/**
+ * @brief CEC clock source.
+ */
+#if !defined(STM32_CECSEL) || defined(__DOXYGEN__)
+#define STM32_CECSEL STM32_CECSEL_LSE_CK
+#endif
+
+/**
+ * @brief USB clock source.
+ */
+#if !defined(STM32_USBSEL) || defined(__DOXYGEN__)
+#define STM32_USBSEL STM32_USBSEL_PLL3_Q_CK
+#endif
+
+#if !defined(STM32H723xx)
+
+/**
+ * @brief I2C123 clock source.
+ */
+#if !defined(STM32_I2C123SEL) || defined(__DOXYGEN__)
+#define STM32_I2C123SEL STM32_I2C123SEL_PCLK1
+#endif
+
+#else // below for defined(STM32H723xx)
+
+#if !defined(STM32_I2C1235SEL) || defined(__DOXYGEN__)
+#define STM32_I2C1235SEL STM32_I2C1235SEL_PCLK1
+#endif
+
+#endif // defined(STM32H723xx)
+
+/**
+ * @brief RNG clock source.
+ */
+#if !defined(STM32_RNGSEL) || defined(__DOXYGEN__)
+#define STM32_RNGSEL STM32_RNGSEL_HSI48_CK
+#endif
+
+#if !defined(STM32H723xx)
+/**
+ * @brief USART16 clock source.
+ */
+#if !defined(STM32_USART16SEL) || defined(__DOXYGEN__)
+#define STM32_USART16SEL STM32_USART16SEL_PCLK2
+#endif
+#else
+/**
+ * @brief USART16910 clock source.
+ */
+#if !defined(STM32_USART16910SEL) || defined(__DOXYGEN__)
+#define STM32_USART16910SEL STM32_USART16910SEL_PCLK2
+#endif
+#endif // !defined(STM32H723xx)
+
+/**
+ * @brief USART234578 clock source.
+ */
+#if !defined(STM32_USART234578SEL) || defined(__DOXYGEN__)
+#define STM32_USART234578SEL STM32_USART234578SEL_PCLK1
+#endif
+
+/**
+ * @brief SPI6SEL clock source.
+ */
+#if !defined(STM32_SPI6SEL) || defined(__DOXYGEN__)
+#define STM32_SPI6SEL STM32_SPI6SEL_PCLK4
+#endif
+
+/**
+ * @brief SAI4BSEL clock source.
+ */
+#if !defined(STM32_SAI4BSEL) || defined(__DOXYGEN__)
+#define STM32_SAI4BSEL STM32_SAI4BSEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief SAI4ASEL clock source.
+ */
+#if !defined(STM32_SAI4ASEL) || defined(__DOXYGEN__)
+#define STM32_SAI4ASEL STM32_SAI4ASEL_PLL1_Q_CK
+#endif
+
+/**
+ * @brief ADCSEL clock source.
+ */
+#if !defined(STM32_ADCSEL) || defined(__DOXYGEN__)
+#define STM32_ADCSEL STM32_ADCSEL_PLL2_P_CK
+#endif
+
+/**
+ * @brief LPTIM345SEL clock source.
+ */
+#if !defined(STM32_LPTIM345SEL) || defined(__DOXYGEN__)
+#define STM32_LPTIM345SEL STM32_LPTIM345SEL_PCLK4
+#endif
+
+/**
+ * @brief LPTIM2SEL clock source.
+ */
+#if !defined(STM32_LPTIM2SEL) || defined(__DOXYGEN__)
+#define STM32_LPTIM2SEL STM32_LPTIM2SEL_PCLK4
+#endif
+
+/**
+ * @brief I2C4SEL clock source.
+ */
+#if !defined(STM32_I2C4SEL) || defined(__DOXYGEN__)
+#define STM32_I2C4SEL STM32_I2C4SEL_PCLK4
+#endif
+
+/**
+ * @brief LPUART1SEL clock source.
+ */
+#if !defined(STM32_LPUART1SEL) || defined(__DOXYGEN__)
+#define STM32_LPUART1SEL STM32_LPUART1SEL_PCLK4
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*
+ * Configuration-related checks.
+ */
+#if !defined(STM32H7xx_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H7xx_MCUCONF not defined"
+#endif
+
+#if defined(STM32H750xx)&& !defined(STM32H750_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H750_MCUCONF not defined"
+#endif
+
+#if defined(STM32H742xx)&& !defined(STM32H742_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H742_MCUCONF not defined"
+#endif
+
+#if defined(STM32H743xx)&& !defined(STM32H743_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H743_MCUCONF not defined"
+#endif
+
+#if defined(STM32H753xx)&& !defined(STM32H753_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H753_MCUCONF not defined"
+#endif
+
+#if defined(STM32H745xx)&& !defined(STM32H745_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H745_MCUCONF not defined"
+#endif
+
+#if defined(STM32H755xx)&& !defined(STM32H755_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H755_MCUCONF not defined"
+#endif
+
+#if defined(STM32H747xx)&& !defined(STM32H747_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H747_MCUCONF not defined"
+#endif
+
+#if defined(STM32H757xx)&& !defined(STM32H757_MCUCONF)
+#error "Using a wrong mcuconf.h file, STM32H757_MCUCONF not defined"
+#endif
+
+/*
+ * Board file checks.
+ */
+#if !defined(STM32_LSECLK)
+#error "STM32_LSECLK not defined in board.h"
+#endif
+#if !defined(STM32_LSEDRV)
+#error "STM32_LSEDRV not defined in board.h"
+#endif
+#if !defined(STM32_HSECLK)
+#error "STM32_HSECLK not defined in board.h"
+#endif
+
+/**
+ * @name Constants depending on VOS and ODEN setting
+ * @{
+ */
+#if STM32_VOS == STM32_VOS_SCALE1
+#define STM32_0WS_THRESHOLD 70000000U
+#define STM32_1WS_THRESHOLD 140000000U
+#define STM32_2WS_THRESHOLD 210000000U
+#define STM32_3WS_THRESHOLD 225000000U
+#define STM32_4WS_THRESHOLD 240000000U
+#define STM32_PLLOUT_MAX 480000000U
+#define STM32_PLLOUT_MIN 1500000U
+
+#elif STM32_VOS == STM32_VOS_SCALE2
+#define STM32_0WS_THRESHOLD 55000000U
+#define STM32_1WS_THRESHOLD 110000000U
+#define STM32_2WS_THRESHOLD 165000000U
+#define STM32_3WS_THRESHOLD 225000000U
+#define STM32_4WS_THRESHOLD 0U
+#define STM32_PLLOUT_MAX 300000000U
+#define STM32_PLLOUT_MIN 1500000U
+
+#elif STM32_VOS == STM32_VOS_SCALE3
+#define STM32_0WS_THRESHOLD 45000000U
+#define STM32_1WS_THRESHOLD 90000000U
+#define STM32_2WS_THRESHOLD 135000000U
+#define STM32_3WS_THRESHOLD 180000000U
+#define STM32_4WS_THRESHOLD 225000000U
+#define STM32_PLLOUT_MAX 200000000U
+#define STM32_PLLOUT_MIN 1500000U
+
+#else
+#error "invalid STM32_VOS setting specified"
+#endif
+/** @} */
+
+/*
+ * HSI related checks.
+ */
+#if STM32_HSI_ENABLED
+#define STM32_HSICLK STM32_HSI_OSC
+
+#else /* !STM32_HSI_ENABLED */
+#define STM32_HSICLK 0U
+
+#if STM32_SW == STM32_SW_HSI_CK
+#error "HSI not enabled, required by STM32_SW"
+#endif
+
+#if (STM32_PLLSRC == STM32_PLLSRC_HSI_CK) && \
+ (STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED)
+#error "HSI not enabled, required by STM32_PLLSRC and STM32_PLLx_ENABLED"
+#endif
+
+#if STM32_CKPERSEL == STM32_CKPERSEL_HSI_CK
+#error "HSI not enabled, required by STM32_CKPERSEL"
+#endif
+
+#if STM32_MCO1SEL == STM32_MCO1SEL_HSI_CK
+#error "HSI not enabled, required by STM32_MCO1SEL"
+#endif
+
+#endif /* !STM32_HSI_ENABLED */
+
+/*
+ * HSI48 related checks.
+ */
+#if STM32_HSI48_ENABLED
+#define STM32_HSI48_CK STM32_HSI48_OSC
+
+#else /* !STM32_HSI48_ENABLED */
+#define STM32_HSI48_CK 0U
+
+#if STM32_MCO1SEL == STM32_MCO1SEL_HSI48_CK
+#error "HSI48 not enabled, required by STM32_MCO1SEL"
+#endif
+
+#endif /* !STM32_HSI48_ENABLED */
+
+/*
+ * CSI related checks.
+ */
+#if STM32_CSI_ENABLED
+#define STM32_CSI_CK STM32_CSI_OSC
+
+#else /* !STM32_CSI_ENABLED */
+#define STM32_CSI_CK 0U
+
+#if STM32_SW == STM32_SW_CSI_CK
+#error "CSI not enabled, required by STM32_SW"
+#endif
+
+#if (STM32_PLLSRC == STM32_PLLSRC_CSI_CK) && \
+ (STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED)
+#error "CSI not enabled, required by STM32_PLLSRC and STM32_PLLx_ENABLED"
+#endif
+
+#if STM32_CKPERSEL == STM32_CKPERSEL_CSI_CK
+#error "CSI not enabled, required by STM32_CKPERSEL"
+#endif
+
+#if STM32_MCO2SEL == STM32_MCO2SEL_CSI_CK
+#error "CSI not enabled, required by STM32_MCO2SEL"
+#endif
+
+#endif /* !STM32_CSI_ENABLED */
+
+/*
+ * HSE related checks.
+ */
+#if STM32_HSE_ENABLED
+
+#if !defined(STM32_HSECLK)
+#error "HSE frequency not defined"
+#endif
+
+#define STM32_HSE_CK STM32_HSECLK
+
+#if STM32_HSECLK == 0
+#error "HSE oscllator not available"
+#else /* STM32_HSECLK != 0 */
+#if defined(STM32_HSE_BYPASS)
+#if (STM32_HSECLK < STM32_HSECLK_BYP_MIN) || (STM32_HSECLK > STM32_HSECLK_BYP_MAX)
+#error "STM32_HSECLK outside acceptable range (STM32_HSECLK_BYP_MIN..STM32_HSECLK_BYP_MAX)"
+#endif
+#else /* !defined(STM32_HSE_BYPASS) */
+#if (STM32_HSECLK < STM32_HSECLK_MIN) || (STM32_HSECLK > STM32_HSECLK_MAX)
+#error "STM32_HSECLK outside acceptable range (STM32_HSECLK_MIN..STM32_HSECLK_MAX)"
+#endif
+#endif /* !defined(STM32_HSE_BYPASS) */
+#endif /* STM32_HSECLK != 0 */
+#else /* !STM32_HSE_ENABLED */
+
+#if STM32_SW == STM32_SW_HSE_CK
+#error "HSE not enabled, required by STM32_SW"
+#endif
+
+#if (STM32_PLLSRC == STM32_PLLSRC_HSE_CK) && \
+ (STM32_PLL1_ENABLED || STM32_PLL2_ENABLED || STM32_PLL3_ENABLED)
+#error "HSE not enabled, required by STM32_PLLSRC and STM32_PLLx_ENABLED"
+#endif
+
+#if STM32_MCO1SEL == STM32_MCO1SEL_HSE_CK
+#error "HSE not enabled, required by STM32_MCO1SEL"
+#endif
+
+#if STM32_MCO2SEL == STM32_MCO2SEL_HSE_CK
+#error "HSE not enabled, required by STM32_MCO2SEL"
+#endif
+
+#if STM32_RTCSEL == STM32_RTCSEL_HSE_1M_CK
+#error "HSE not enabled, required by STM32_RTCSEL"
+#endif
+
+#endif /* !STM32_HSE_ENABLED */
+
+/*
+ * LSI related checks.
+ */
+#if STM32_LSI_ENABLED
+#define STM32_LSI_CK STM32_LSI_OSC
+
+#else /* !STM32_LSI_ENABLED */
+#define STM32_LSI_CK 0U
+
+#if STM32_RTCSEL == STM32_RTCSEL_LSI_CK
+#error "LSI not enabled, required by STM32_RTCSEL"
+#endif
+
+#if STM32_MCO2SEL == STM32_MCO2SEL_LSI_CK
+#error "HSE not enabled, required by STM32_MCO2SEL"
+#endif
+
+#endif /* !STM32_LSI_ENABLED */
+
+/*
+ * LSE related checks.
+ */
+#if STM32_LSE_ENABLED
+
+#if !defined(STM32_LSECLK)
+#error "LSE frequency not defined"
+#endif
+
+#define STM32_LSE_CK STM32_LSECLK
+
+#if (STM32_LSE_CK == 0)
+#error "LSE oscillator not available"
+#endif
+
+#if defined(STM32_LSE_BYPASS)
+#if (STM32_LSE_CK < STM32_LSE_CK_MIN) || (STM32_LSE_CK > STM32_LSE_CK_BYP_MAX)
+#error "STM32_LSE_CK outside acceptable range (STM32_LSE_CK_MIN..STM32_LSE_CK_BYP_MAX)"
+#endif
+#else
+#if (STM32_LSE_CK < STM32_LSE_CK_MIN) || (STM32_LSE_CK > STM32_LSE_CK_MAX)
+#error "STM32_LSE_CK outside acceptable range (STM32_LSE_CK_MIN..STM32_LSE_CK_MAX)"
+#endif
+#endif
+
+#if !defined(STM32_LSEDRV)
+#error "STM32_LSEDRV not defined"
+#endif
+
+#if (STM32_LSEDRV >> 3) > 3
+#error "STM32_LSEDRV outside acceptable range ((0<<3)..(3<<3))"
+#endif
+
+#else /* !STM32_LSE_ENABLED */
+
+#if STM32_RTCSEL == STM32_RTCSEL_LSE_CK
+#error "LSE not enabled, required by STM32_RTCSEL"
+#endif
+
+#if STM32_MCO1SEL == STM32_MCO1SEL_LSE_CK
+#error "LSE not enabled, required by STM32_MCO1SEL"
+#endif
+
+#endif /* !STM32_LSE_ENABLED */
+
+/**
+ * @brief HSI divided clock.
+ */
+#if (STM32_HSIDIV == STM32_HSIDIV_DIV1) || defined(__DOXYGEN__)
+#define STM32_HSI_CK (STM32_HSICLK / 1U)
+#elif STM32_HSIDIV == STM32_HSIDIV_DIV2
+#define STM32_HSI_CK (STM32_HSICLK / 2U)
+#elif STM32_HSIDIV == STM32_HSIDIV_DIV4
+#define STM32_HSI_CK (STM32_HSICLK / 4U)
+#elif STM32_HSIDIV == STM32_HSIDIV_DIV8
+#define STM32_HSI_CK (STM32_HSICLK / 8U)
+#else
+#error "invalid STM32_HSIDIV value specified"
+#endif
+
+/**
+ * @brief HSE divided clock for RTC.
+ */
+#if ((STM32_RTCPRE_VALUE >= 2) && (STM32_RTCPRE_VALUE <= 63)) || \
+ defined(__DOXYGEN__)
+#define STM32_HSE_1M_CK (STM32_HSE_CK / STM32_RTCPRE_VALUE)
+#else
+#error "invalid STM32_RTCPRE_VALUE value specified"
+#endif
+
+/**
+ * @brief PLLs input clock frequency.
+ */
+#if (STM32_PLLSRC == STM32_PLLSRC_HSE_CK) || defined(__DOXYGEN__)
+#define STM32_PLLCLKIN STM32_HSE_CK
+
+#elif STM32_PLLSRC == STM32_PLLSRC_HSI_CK
+#define STM32_PLLCLKIN STM32_HSI_CK
+
+#elif STM32_PLLSRC == STM32_PLLSRC_CSI_CK
+#define STM32_PLLCLKIN STM32_CSI_CK
+
+#elif STM32_PLLSRC == STM32_PLLSRC_DISABLE
+
+#else
+#error "invalid STM32_PLLSRC value specified"
+#endif
+
+#if STM32_PLLSRC != STM32_PLLSRC_DISABLE
+
+/**
+ * @brief PLL1 DIVM field.
+ */
+#if ((STM32_PLL1_DIVM_VALUE >= 1) && (STM32_PLL1_DIVM_VALUE <= 63)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL1_DIVM (STM32_PLL1_DIVM_VALUE << 4)
+#define STM32_PLL1_REF_CK (STM32_PLLCLKIN / STM32_PLL1_DIVM_VALUE)
+#else
+#error "invalid STM32_PLL1_DIVM_VALUE value specified"
+#endif
+
+/*
+ * PLL1 input frequency range check.
+ */
+#if (STM32_PLL1_REF_CK < STM32_PLLIN_MIN) || (STM32_PLL1_REF_CK > STM32_PLLIN_MAX)
+#error "STM32_PLL1_REF_CK outside acceptable range (STM32_PLLIN_MIN..STM32_PLLIN_MAX)"
+#endif
+
+/**
+ * @brief PLL1 input range selector.
+ */
+#if (STM32_PLL1_REF_CK < STM32_PLLIN_THRESHOLD1) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_0
+#elif STM32_PLL1_REF_CK < STM32_PLLIN_THRESHOLD2
+#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_1
+#elif STM32_PLL1_REF_CK < STM32_PLLIN_THRESHOLD3
+#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_2
+#else
+#define STM32_PLLCFGR_PLL1RGE RCC_PLLCFGR_PLL1RGE_3
+#endif
+
+/**
+ * @brief PLL2 DIVM field.
+ */
+#if ((STM32_PLL2_DIVM_VALUE >= 1) && (STM32_PLL2_DIVM_VALUE <= 63)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL2_DIVM (STM32_PLL2_DIVM_VALUE << 12)
+#define STM32_PLL2_REF_CK (STM32_PLLCLKIN / STM32_PLL2_DIVM_VALUE)
+#else
+#error "invalid STM32_PLL2_DIVM_VALUE value specified"
+#endif
+
+/*
+ * PLL2 input frequency range check.
+ */
+#if (STM32_PLL2_REF_CK < STM32_PLLIN_MIN) || (STM32_PLL2_REF_CK > STM32_PLLIN_MAX)
+#error "STM32_PLL2_REF_CK outside acceptable range (STM32_PLLIN_MIN..STM32_PLLIN_MAX)"
+#endif
+
+/**
+ * @brief PLL2 input range selector.
+ */
+#if (STM32_PLL2_REF_CK < STM32_PLLIN_THRESHOLD1) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_0
+#elif STM32_PLL2_REF_CK < STM32_PLLIN_THRESHOLD2
+#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_1
+#elif STM32_PLL2_REF_CK < STM32_PLLIN_THRESHOLD3
+#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_2
+#else
+#define STM32_PLLCFGR_PLL2RGE RCC_PLLCFGR_PLL2RGE_3
+#endif
+
+/**
+ * @brief PLL3 DIVM field.
+ */
+#if ((STM32_PLL3_DIVM_VALUE >= 1) && (STM32_PLL3_DIVM_VALUE <= 63)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3_DIVM (STM32_PLL3_DIVM_VALUE << 20)
+#define STM32_PLL3_REF_CK (STM32_PLLCLKIN / STM32_PLL3_DIVM_VALUE)
+#else
+#error "invalid STM32_PLL3_DIVM_VALUE value specified"
+#endif
+
+/*
+ * PLL3 input frequency range check.
+ */
+#if (STM32_PLL3_REF_CK < STM32_PLLIN_MIN) || (STM32_PLL3_REF_CK > STM32_PLLIN_MAX)
+#error "STM32_PLL3_REF_CK outside acceptable range (STM32_PLLIN_MIN..STM32_PLLIN_MAX)"
+#endif
+
+/**
+ * @brief PLL3 input range selector.
+ */
+#if (STM32_PLL3_REF_CK < STM32_PLLIN_THRESHOLD1) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_0
+#elif STM32_PLL3_REF_CK < STM32_PLLIN_THRESHOLD2
+#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_1
+#elif STM32_PLL3_REF_CK < STM32_PLLIN_THRESHOLD3
+#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_2
+#else
+#define STM32_PLLCFGR_PLL3RGE RCC_PLLCFGR_PLL3RGE_3
+#endif
+
+/**
+ * @brief PLL1 DIVN field.
+ */
+#if ((STM32_PLL1_DIVN_VALUE >= 4) && (STM32_PLL1_DIVN_VALUE <= 512)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL1_DIVN ((STM32_PLL1_DIVN_VALUE - 1U) << 0U)
+#else
+#error "invalid STM32_PLL1_DIVN_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL2 DIVN field.
+ */
+#if ((STM32_PLL2_DIVN_VALUE >= 4) && (STM32_PLL2_DIVN_VALUE <= 512)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL2_DIVN ((STM32_PLL2_DIVN_VALUE - 1U) << 0U)
+#else
+#error "invalid STM32_PLL2_DIVN_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL3 DIVN field.
+ */
+#if ((STM32_PLL3_DIVN_VALUE >= 4) && (STM32_PLL3_DIVN_VALUE <= 512)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3_DIVN ((STM32_PLL3_DIVN_VALUE - 1U) << 0U)
+#else
+#error "invalid STM32_PLL3_DIVN_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL1 FRACN field.
+ */
+#if ((STM32_PLL1_FRACN_VALUE >= 0) && (STM32_PLL1_FRACN_VALUE <= 8191)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL1_FRACN (STM32_PLL1_FRACN_VALUE << 3U)
+#else
+#error "invalid STM32_PLL1_FRACN_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL2 FRACN field.
+ */
+#if ((STM32_PLL2_FRACN_VALUE >= 0) && (STM32_PLL2_FRACN_VALUE <= 8191)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL2_FRACN (STM32_PLL2_FRACN_VALUE << 3U)
+#else
+#error "invalid STM32_PLL2_FRACN_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL3 FRACN field.
+ */
+#if ((STM32_PLL3_FRACN_VALUE >= 0) && (STM32_PLL3_FRACN_VALUE <= 8191)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3_FRACN (STM32_PLL3_FRACN_VALUE << 3U)
+#else
+#error "invalid STM32_PLL3_FRACN_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL1 DIVP field.
+ */
+#if ((STM32_PLL1_DIVP_VALUE >= 2) && (STM32_PLL1_DIVP_VALUE <= 128) && \
+ ((STM32_PLL1_DIVP_VALUE & 1U) == 0U)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL1_DIVP ((STM32_PLL1_DIVP_VALUE - 1U) << 9U)
+#else
+#error "invalid STM32_PLL1_DIVP_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL2 DIVP field.
+ */
+#if ((STM32_PLL2_DIVP_VALUE >= 2) && (STM32_PLL2_DIVP_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL2_DIVP ((STM32_PLL2_DIVP_VALUE - 1U) << 9U)
+#else
+#error "invalid STM32_PLL2_DIVP_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL3 DIVP field.
+ */
+#if ((STM32_PLL3_DIVP_VALUE >= 2) && (STM32_PLL3_DIVP_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3_DIVP ((STM32_PLL3_DIVP_VALUE - 1U) << 9U)
+#else
+#error "invalid STM32_PLL3_DIVP_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL1 DIVQ field.
+ */
+#if ((STM32_PLL1_DIVQ_VALUE >= 1) && (STM32_PLL1_DIVQ_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL1_DIVQ ((STM32_PLL1_DIVQ_VALUE - 1U) << 16U)
+#else
+#error "invalid STM32_PLL1_DIVQ_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL2 DIVQ field.
+ */
+#if ((STM32_PLL2_DIVQ_VALUE >= 1) && (STM32_PLL2_DIVQ_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL2_DIVQ ((STM32_PLL2_DIVQ_VALUE - 1U) << 16U)
+#else
+#error "invalid STM32_PLL2_DIVQ_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL3 DIVQ field.
+ */
+#if ((STM32_PLL3_DIVQ_VALUE >= 1) && (STM32_PLL3_DIVQ_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3_DIVQ ((STM32_PLL3_DIVQ_VALUE - 1U) << 16U)
+#else
+#error "invalid STM32_PLL3_DIVQ_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL1 DIVR field.
+ */
+#if ((STM32_PLL1_DIVR_VALUE >= 1) && (STM32_PLL1_DIVR_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL1_DIVR ((STM32_PLL1_DIVR_VALUE - 1U) << 24U)
+#else
+#error "invalid STM32_PLL1_DIVR_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL2 DIVR field.
+ */
+#if ((STM32_PLL2_DIVR_VALUE >= 1) && (STM32_PLL2_DIVR_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL2_DIVR ((STM32_PLL2_DIVR_VALUE - 1U) << 24U)
+#else
+#error "invalid STM32_PLL2_DIVR_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL3 DIVR field.
+ */
+#if ((STM32_PLL3_DIVR_VALUE >= 1) && (STM32_PLL3_DIVR_VALUE <= 128)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3_DIVR ((STM32_PLL3_DIVR_VALUE - 1U) << 24U)
+#else
+#error "invalid STM32_PLL3_DIVR_VALUE value specified"
+#endif
+
+/**
+ * @brief PLL1 VCO frequency.
+ */
+#define STM32_PLL1_VCO_CK (STM32_PLL1_REF_CK * STM32_PLL1_DIVN_VALUE)
+
+/*
+ * PLL1 VCO frequency range check.
+ */
+#if (STM32_PLL1_VCO_CK < STM32_PLLVCO_MIN) || (STM32_PLL1_VCO_CK > STM32_PLLVCO_MAX)
+#error "STM32_PLL1_VCO_CK outside acceptable range (STM32_PLLVCO_MIN..STM32_PLLVCO_MAX)"
+#endif
+
+/*
+ * PLL1 VCO mode.
+ */
+#if (STM32_PLL1_VCO_CK > STM32_PLLVCO_THRESHOLD) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_PLL1VCOSEL 0U
+#else
+#define STM32_PLLCFGR_PLL1VCOSEL RCC_PLLCFGR_PLL1VCOSEL
+#endif
+
+/**
+ * @brief PLL2 VCO frequency.
+ */
+#define STM32_PLL2_VCO_CK (STM32_PLL2_REF_CK * STM32_PLL2_DIVN_VALUE)
+
+/*
+ * PLL2 VCO frequency range check.
+ */
+#if STM32_PLL2_ENABLED == TRUE
+#if (STM32_PLL2_VCO_CK < STM32_PLLVCO_MIN) || (STM32_PLL2_VCO_CK > STM32_PLLVCO_MAX)
+#error "STM32_PLL2_VCO_CK outside acceptable range (STM32_PLLVCO_MIN..STM32_PLLVCO_MAX)"
+#endif
+#endif // STM32_PLL2_ENABLED == TRUE
+
+/*
+ * PLL2 VCO mode.
+ */
+#if (STM32_PLL2_VCO_CK > STM32_PLLVCO_THRESHOLD) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_PLL2VCOSEL 0U
+#else
+#define STM32_PLLCFGR_PLL2VCOSEL RCC_PLLCFGR_PLL2VCOSEL
+#endif
+
+/**
+ * @brief PLL3 VCO frequency.
+ */
+#define STM32_PLL3_VCO_CK (STM32_PLL3_REF_CK * STM32_PLL3_DIVN_VALUE)
+
+/*
+ * PLL3 VCO frequency range check.
+ */
+#if STM32_PLL3_ENABLED == TRUE
+#if (STM32_PLL3_VCO_CK < STM32_PLLVCO_MIN) || (STM32_PLL3_VCO_CK > STM32_PLLVCO_MAX)
+#error "STM32_PLL3_VCO_CK outside acceptable range (STM32_PLLVCO_MIN..STM32_PLLVCO_MAX)"
+#endif
+#endif // STM32_PLL3_ENABLED == TRUE
+
+/*
+ * PLL3 VCO mode.
+ */
+#if (STM32_PLL3_VCO_CK > STM32_PLLVCO_THRESHOLD) || defined(__DOXYGEN__)
+#define STM32_PLLCFGR_PLL3VCOSEL 0U
+#else
+#define STM32_PLLCFGR_PLL3VCOSEL RCC_PLLCFGR_PLL3VCOSEL
+#endif
+
+#endif // STM32_PLLSRC != STM32_PLLSRC_DISABLE
+
+#if ((STM32_PLL1_ENABLED == TRUE) && (STM32_PLL1_P_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL1 P output clock frequency.
+ */
+#define STM32_PLL1_P_CK (STM32_PLL1_VCO_CK / STM32_PLL1_DIVP_VALUE)
+
+/*
+ * PLL1 P output frequency range check.
+ */
+#if (STM32_PLL1_P_CK < STM32_PLLOUT_MIN) || (STM32_PLL1_P_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL1_P_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL1_P_CK 0U
+#endif
+
+#if ((STM32_PLL2_ENABLED == TRUE) && (STM32_PLL2_P_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL2 P output clock frequency.
+ */
+#define STM32_PLL2_P_CK (STM32_PLL2_VCO_CK / STM32_PLL2_DIVP_VALUE)
+
+/*
+ * PLL2 P output frequency range check.
+ */
+#if (STM32_PLL2_P_CK < STM32_PLLOUT_MIN) || (STM32_PLL2_P_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL2_P_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL2_P_CK 0U
+#endif
+
+#if ((STM32_PLL3_ENABLED == TRUE) && (STM32_PLL3_P_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL3 P output clock frequency.
+ */
+#define STM32_PLL3_P_CK (STM32_PLL3_VCO_CK / STM32_PLL3_DIVP_VALUE)
+
+/*
+ * PLL3 P output frequency range check.
+ */
+#if (STM32_PLL3_P_CK < STM32_PLLOUT_MIN) || (STM32_PLL3_P_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL3_P_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL3_P_CK 0U
+#endif
+
+#if ((STM32_PLL1_ENABLED == TRUE) && (STM32_PLL1_Q_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL1 Q output clock frequency.
+ */
+#define STM32_PLL1_Q_CK (STM32_PLL1_VCO_CK / STM32_PLL1_DIVQ_VALUE)
+
+/*
+ * PLL1 Q output frequency range check.
+ */
+#if (STM32_PLL1_Q_CK < STM32_PLLOUT_MIN) || (STM32_PLL1_Q_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL1_Q_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL1_Q_CK 0U
+#endif
+
+#if ((STM32_PLL2_ENABLED == TRUE) && (STM32_PLL2_Q_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL2 Q output clock frequency.
+ */
+#define STM32_PLL2_Q_CK (STM32_PLL2_VCO_CK / STM32_PLL2_DIVQ_VALUE)
+
+/*
+ * PLL2 Q output frequency range check.
+ */
+#if (STM32_PLL2_Q_CK < STM32_PLLOUT_MIN) || (STM32_PLL2_Q_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL2_Q_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL2_Q_CK 0U
+#endif
+
+#if ((STM32_PLL3_ENABLED == TRUE) && (STM32_PLL3_Q_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL3 Q output clock frequency.
+ */
+#define STM32_PLL3_Q_CK (STM32_PLL3_VCO_CK / STM32_PLL3_DIVQ_VALUE)
+
+/*
+ * PLL3 Q output frequency range check.
+ */
+#if (STM32_PLL3_Q_CK < STM32_PLLOUT_MIN) || (STM32_PLL3_Q_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL3_Q_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL3_Q_CK 0U
+#endif
+
+#if ((STM32_PLL1_ENABLED == TRUE) && (STM32_PLL1_R_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL1 R output clock frequency.
+ */
+#define STM32_PLL1_R_CK (STM32_PLL1_VCO_CK / STM32_PLL1_DIVR_VALUE)
+
+/*
+ * PLL1 R output frequency range check.
+ */
+#if (STM32_PLL1_R_CK < STM32_PLLOUT_MIN) || (STM32_PLL1_R_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL1_R_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL1_R_CK 0U
+#endif
+
+#if ((STM32_PLL2_ENABLED == TRUE) && (STM32_PLL2_R_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL2 R output clock frequency.
+ */
+#define STM32_PLL2_R_CK (STM32_PLL2_VCO_CK / STM32_PLL2_DIVR_VALUE)
+
+/*
+ * PLL2 R output frequency range check.
+ */
+#if (STM32_PLL2_R_CK < STM32_PLLOUT_MIN) || (STM32_PLL2_R_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL2_R_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL2_R_CK 0U
+#endif
+
+#if ((STM32_PLL3_ENABLED == TRUE) && (STM32_PLL3_R_ENABLED == TRUE)) || \
+ defined(__DOXYGEN__)
+/**
+ * @brief PLL3 R output clock frequency.
+ */
+#define STM32_PLL3_R_CK (STM32_PLL3_VCO_CK / STM32_PLL3_DIVR_VALUE)
+
+/*
+ * PLL3 R output frequency range check.
+ */
+#if (STM32_PLL3_R_CK < STM32_PLLOUT_MIN) || (STM32_PLL3_R_CK > STM32_PLLOUT_MAX)
+#error "STM32_PLL3_R_CLKOUT outside acceptable range (STM32_PLLOUT_MIN..STM32_PLLOUT_MAX)"
+#endif
+#else
+#define STM32_PLL3_R_CK 0U
+#endif
+
+/**
+ * @brief System clock source.
+ */
+#if (STM32_SW == STM32_SW_HSI_CK) || defined(__DOXYGEN__)
+#define STM32_SYS_CK STM32_HSI_CK
+
+#elif (STM32_SW == STM32_SW_CSI_CK)
+#define STM32_SYS_CK STM32_CSI_CK
+
+#elif (STM32_SW == STM32_SW_HSE_CK)
+#define STM32_SYS_CK STM32_HSE_CK
+
+#elif (STM32_SW == STM32_SW_PLL1_P_CK)
+#define STM32_SYS_CK STM32_PLL1_P_CK
+
+#else
+#error "invalid STM32_SW value specified"
+#endif
+
+/*
+ * Check on the system clock.
+ */
+#if STM32_SYS_CK > STM32_SYSCLK_MAX
+#error "STM32_SYS_CK above maximum rated frequency (STM32_SYSCLK_MAX)"
+#endif
+
+/*
+ * ODEN setting based on clock frequency.
+ */
+#if STM32_SYS_CK > STM32_SYSCLK_MAX_NOBOOST
+#define STM32_ODEN STM32_ODEN_ENABLED
+#else
+#define STM32_ODEN STM32_ODEN_DISABLED
+#endif
+
+/**
+ * @brief Peripherals clock source.
+ */
+#if (STM32_CKPERSEL == STM32_CKPERSEL_HSI_CK) || defined(__DOXYGEN__)
+#define STM32_PER_CK STM32_HSI_CK
+
+#elif (STM32_CKPERSEL == STM32_CKPERSEL_CSI_CK)
+#define STM32_PER_CK STM32_CSI_CK
+
+#elif (STM32_CKPERSEL == STM32_CKPERSEL_HSE_CK)
+#define STM32_PER_CK STM32_HSE_CK
+
+#else
+#error "invalid STM32_CKPERSEL value specified"
+#endif
+
+/*
+ * Check on the peripherals clock.
+ */
+#if STM32_PER_CK > STM32_HCLK_MAX
+#error "STM32_PER_CK above maximum rated frequency (STM32_HCLK_MAX)"
+#endif
+
+/**
+ * @brief MCO1 divider clock.
+ */
+#if (STM32_MCO1SEL == STM32_MCO1SEL_HSI_CK) || defined(__DOXYGEN__)
+#define STM32_MCO1DIVCLK STM32_HSI_CK
+
+#elif STM32_MCO1SEL == STM32_MCO1SEL_LSE_CK
+#define STM32_MCO1DIVCLK STM32_LSE_CK
+
+#elif STM32_MCO1SEL == STM32_MCO1SEL_HSE_CK
+#define STM32_MCO1DIVCLK STM32_HSE_CK
+
+#elif STM32_MCO1SEL == STM32_MCO1SEL_PLL1_Q_CK
+#define STM32_MCO1DIVCLK STM32_PLL1_P_CK
+
+#elif STM32_MCO1SEL == STM32_MCO1SEL_HSI48_CK
+#define STM32_MCO1DIVCLK STM32_HSI48_CK
+
+#else
+#error "invalid STM32_MCO1SEL value specified"
+#endif
+
+/**
+ * @brief MCO1 output pin clock.
+ */
+#if (STM32_MCO1PRE_VALUE < 1) || (STM32_MCO1PRE_VALUE > 15)
+#error "STM32_MCO1PRE_VALUE outside acceptable range (1..15)"
+#endif
+
+/**
+ * @brief MCO2 divider clock.
+ */
+#if (STM32_MCO2SEL == STM32_MCO2SEL_SYS_CK) || defined(__DOXYGEN__)
+#define STM32_MCO2DIVCLK STM32_SYS_CK
+
+#elif STM32_MCO2SEL == STM32_MCO2SEL_PLL1_P_CK
+#define STM32_MCO2DIVCLK STM32_PLL2_P_CK
+
+#elif STM32_MCO2SEL == STM32_MCO2SEL_HSE_CK
+#define STM32_MCO2DIVCLK STM32_HSE_CK
+
+#elif STM32_MCO2SEL == STM32_MCO2SEL_PLL2_P_CK
+#define STM32_MCO2DIVCLK STM32_PLL2_P_CK
+
+#elif STM32_MCO2SEL == STM32_MCO2SEL_CSI_CK
+#define STM32_MCO2DIVCLK STM32_CSI_CK
+
+#elif STM32_MCO2SEL == STM32_MCO2SEL_LSI_CK
+#define STM32_MCO2DIVCLK STM32_LSI_CK
+
+#else
+#error "invalid STM32_MCO2SEL value specified"
+#endif
+
+/**
+ * @brief MCO2 output pin clock.
+ */
+#if (STM32_MCO2PRE_VALUE < 1) || (STM32_MCO2PRE_VALUE > 15)
+#error "STM32_MCO2PRE_VALUE outside acceptable range (1..15)"
+#endif
+
+/**
+ * @brief RTC clock.
+ */
+#if (STM32_RTCSEL == STM32_RTCSEL_NOCLK) || defined(__DOXYGEN__)
+#define STM32_RTC_CK 0
+
+#elif STM32_RTCSEL == STM32_RTCSEL_LSE_CK
+#define STM32_RTC_CK STM32_LSE_CK
+
+#elif STM32_RTCSEL == STM32_RTCSEL_LSI_CK
+#define STM32_RTC_CK STM32_LSI_CK
+
+#elif STM32_RTCSEL == STM32_RTCSEL_HSE_1M_CK
+#define STM32_RTC_CK STM32_HSE_1M_CK
+
+#else
+#error "invalid STM32_RTCSEL value specified"
+#endif
+
+/*
+ * Check on the RTC clock.
+ */
+#if STM32_RTC_CK > 1000000
+#error "STM32_RTC_CK above maximum rated frequency (1000000)"
+#endif
+
+/**
+ * @brief D1CPRE clock.
+ */
+#if (STM32_D1CPRE == STM32_D1CPRE_DIV1) || defined(__DOXYGEN__)
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 1U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV2
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 2U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV4
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 4U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV8
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 8U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV16
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 16U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV64
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 64U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV128
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 128U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV256
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 256U)
+#elif STM32_D1CPRE == STM32_D1CPRE_DIV512
+#define STM32_SYS_D1CPRE_CK (STM32_SYS_CK / 512U)
+#else
+#error "invalid STM32_D1CPRE value specified"
+#endif
+
+/**
+ * @brief HCLK clock.
+ */
+#if (STM32_D1HPRE == STM32_D1HPRE_DIV1) || defined(__DOXYGEN__)
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 1U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV2
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 2U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV4
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 4U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV8
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 8U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV16
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 16U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV64
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 64U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV128
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 128U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV256
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 256U)
+#elif STM32_D1HPRE == STM32_D1HPRE_DIV512
+#define STM32_HCLK (STM32_SYS_D1CPRE_CK / 512U)
+#else
+#error "invalid STM32_D1HPRE value specified"
+#endif
+
+/**
+ * @brief Core clock.
+ */
+#define STM32_CORE1_CK STM32_SYS_D1CPRE_CK
+
+/**
+ * @brief Core clock.
+ */
+#define STM32_CORE2_CK STM32_HCLK
+
+#if (STM32_TARGET_CORE == 1) || defined(__DOXYGEN__)
+
+#if STM32_HAS_M7 != TRUE
+#error "Cortex-M7 not present in this device"
+#endif
+#define STM32_CORE_CK STM32_CORE1_CK
+
+#elif STM32_TARGET_CORE == 2
+
+#if STM32_HAS_M4 != TRUE
+#error "Cortex-M4 not present in this device"
+#endif
+#define STM32_CORE_CK STM32_CORE2_CK
+
+#else
+#error "invalid STM32_TARGET_CORE value specified"
+#endif
+
+/*
+ * AHB frequency check.
+ */
+#if STM32_HCLK > STM32_HCLK_MAX
+#error "STM32_HCLK exceeding maximum frequency (STM32_HCLK_MAX)"
+#endif
+
+/**
+ * @brief D1 PCLK3 clock.
+ */
+#if (STM32_D1PPRE3 == STM32_D1PPRE3_DIV1) || defined(__DOXYGEN__)
+#define STM32_PCLK3 (STM32_HCLK / 1U)
+#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV2
+#define STM32_PCLK3 (STM32_HCLK / 2U)
+#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV4
+#define STM32_PCLK3 (STM32_HCLK / 4U)
+#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV8
+#define STM32_PCLK3 (STM32_HCLK / 8U)
+#elif STM32_D1PPRE3 == STM32_D1PPRE3_DIV16
+#define STM32_PCLK3 (STM32_HCLK / 16U)
+#else
+#error "invalid STM32_D1PPRE3 value specified"
+#endif
+
+/*
+ * D1 PCLK3 frequency check.
+ */
+#if STM32_PCLK3 > STM32_PCLK3_MAX
+#error "STM32_PCLK3 exceeding maximum frequency (STM32_PCLK3_MAX)"
+#endif
+
+/**
+ * @brief D2 PCLK1 clock.
+ */
+#if (STM32_D2PPRE1 == STM32_D2PPRE1_DIV1) || defined(__DOXYGEN__)
+#define STM32_PCLK1 (STM32_HCLK / 1U)
+#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV2
+#define STM32_PCLK1 (STM32_HCLK / 2U)
+#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV4
+#define STM32_PCLK1 (STM32_HCLK / 4U)
+#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV8
+#define STM32_PCLK1 (STM32_HCLK / 8U)
+#elif STM32_D2PPRE1 == STM32_D2PPRE1_DIV16
+#define STM32_PCLK1 (STM32_HCLK / 16U)
+#else
+#error "invalid STM32_D2PPRE1 value specified"
+#endif
+
+/*
+ * D2 PCLK1 frequency check.
+ */
+#if STM32_PCLK1 > STM32_PCLK1_MAX
+#error "STM32_PCLK1 exceeding maximum frequency (STM32_PCLK1_MAX)"
+#endif
+
+/**
+ * @brief D2 PCLK2 clock.
+ */
+#if (STM32_D2PPRE2 == STM32_D2PPRE2_DIV1) || defined(__DOXYGEN__)
+#define STM32_PCLK2 (STM32_HCLK / 1U)
+#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV2
+#define STM32_PCLK2 (STM32_HCLK / 2U)
+#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV4
+#define STM32_PCLK2 (STM32_HCLK / 4U)
+#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV8
+#define STM32_PCLK2 (STM32_HCLK / 8U)
+#elif STM32_D2PPRE2 == STM32_D2PPRE2_DIV16
+#define STM32_PCLK2 (STM32_HCLK / 16U)
+#else
+#error "invalid STM32_D2PPRE2 value specified"
+#endif
+
+/*
+ * D2 PCLK2 frequency check.
+ */
+#if STM32_PCLK2 > STM32_PCLK2_MAX
+#error "STM32_PCLK2 exceeding maximum frequency (STM32_PCLK2_MAX)"
+#endif
+
+/**
+ * @brief D3 PCLK4 clock.
+ */
+#if (STM32_D3PPRE4 == STM32_D3PPRE4_DIV1) || defined(__DOXYGEN__)
+#define STM32_PCLK4 (STM32_HCLK / 1U)
+#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV2
+#define STM32_PCLK4 (STM32_HCLK / 2U)
+#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV4
+#define STM32_PCLK4 (STM32_HCLK / 4U)
+#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV8
+#define STM32_PCLK4 (STM32_HCLK / 8U)
+#elif STM32_D3PPRE4 == STM32_D3PPRE4_DIV16
+#define STM32_PCLK4 (STM32_HCLK / 16U)
+#else
+#error "invalid STM32_D3PPRE4 value specified"
+#endif
+
+/*
+ * D3 PCLK4 frequency check.
+ */
+#if STM32_PCLK4 > STM32_PCLK4_MAX
+#error "STM32_PCLK4 exceeding maximum frequency (STM32_PCLK4_MAX)"
+#endif
+
+/**
+ * @brief Flash settings.
+ */
+#if (STM32_HCLK <= STM32_0WS_THRESHOLD) || defined(__DOXYGEN__)
+#define STM32_FLASHBITS 0x00000000
+
+#elif STM32_HCLK <= STM32_1WS_THRESHOLD
+#define STM32_FLASHBITS 0x00000001
+
+#elif STM32_HCLK <= STM32_2WS_THRESHOLD
+#define STM32_FLASHBITS 0x00000002
+
+#elif STM32_HCLK <= STM32_3WS_THRESHOLD
+#define STM32_FLASHBITS 0x00000003
+
+#elif STM32_HCLK <= STM32_4WS_THRESHOLD
+#define STM32_FLASHBITS 0x00000004
+
+#else
+#define STM32_FLASHBITS 0x00000007
+#endif
+
+#if (STM32_D2PPRE1 == STM32_D2PPRE1_DIV1) || defined(__DOXYGEN__)
+/**
+ * @brief Clock of timers connected to APB1
+ */
+#define STM32_TIMCLK1 (STM32_PCLK1 * 1)
+#else
+#if (STM32_TIMPRE_ENABLE == FALSE) || (STM32_D2PPRE1 == STM32_D2PPRE1_DIV2)
+#define STM32_TIMCLK1 (STM32_PCLK1 * 2)
+#else
+#define STM32_TIMCLK1 (STM32_PCLK1 * 4)
+#endif
+#endif
+
+#if (STM32_D2PPRE2 == STM32_D2PPRE2_DIV1) || defined(__DOXYGEN__)
+/**
+ * @brief Clock of timers connected to APB2.
+ */
+#define STM32_TIMCLK2 (STM32_PCLK2 * 1)
+#else
+#if (STM32_TIMPRE_ENABLE == FALSE) || (STM32_D2PPRE2 == STM32_D2PPRE2_DIV2)
+#define STM32_TIMCLK2 (STM32_PCLK2 * 2)
+#else
+#define STM32_TIMCLK2 (STM32_PCLK2 * 4)
+#endif
+#endif
+
+#if (STM32_LPTIM1SEL == STM32_LPTIM1SEL_PCLK1) || defined(__DOXYGEN__)
+/**
+ * @brief LPTIM1 clock.
+ */
+#define STM32_LPTIM1CLK STM32_PCLK1
+
+#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_PLL2_P_CK
+#define STM32_LPTIM1CLK STM32_PLL2_P_CK
+#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_PLL3_R_CK
+#define STM32_LPTIM1CLK STM32_PLL3_R_CK
+#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_LSE_CK
+#define STM32_LPTIM1CLK STM32_LSE_CK
+#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_LSI_CK
+#define STM32_LPTIM1CLK STM32_LSI_CK
+#elif STM32_LPTIM1SEL == STM32_LPTIM1SEL_PER_CK
+#define STM32_LPTIM1CLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_LPTIM1SEL clock"
+#endif
+
+#if (STM32_LPTIM2SEL == STM32_LPTIM2SEL_PCLK4) || defined(__DOXYGEN__)
+/**
+ * @brief LPTIM2 clock.
+ */
+#define STM32_LPTIM2CLK STM32_PCLK4
+
+#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_PLL2_P_CK
+#define STM32_LPTIM2CLK STM32_PLL2_P_CK
+#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_PLL3_P_CK
+#define STM32_LPTIM2CLK STM32_PLL3_P_CK
+#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_LSE_CK
+#define STM32_LPTIM2CLK STM32_LSE_CK
+#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_LSI_CK
+#define STM32_LPTIM2CLK STM32_LSI_CK
+#elif STM32_LPTIM2SEL == STM32_LPTIM2SEL_PER_CK
+#define STM32_LPTIM2CLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_LPTIM2SEL clock"
+#endif
+
+#if (STM32_LPTIM345SEL == STM32_LPTIM345SEL_PCLK4) || defined(__DOXYGEN__)
+/**
+ * @brief LPTIM3 clock.
+ */
+#define STM32_LPTIM3CLK STM32_PCLK4
+
+/**
+ * @brief LPTIM4 clock.
+ */
+#define STM32_LPTIM4CLK STM32_PCLK4
+
+/**
+ * @brief LPTIM5 clock.
+ */
+#define STM32_LPTIM5CLK STM32_PCLK4
+
+#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_PLL2_P_CK
+#define STM32_LPTIM3CLK STM32_PLL2_P_CK
+#define STM32_LPTIM4CLK STM32_PLL2_P_CK
+#define STM32_LPTIM5CLK STM32_PLL2_P_CK
+#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_PLL3_P_CK
+#define STM32_LPTIM3CLK STM32_PLL3_P_CK
+#define STM32_LPTIM4CLK STM32_PLL3_P_CK
+#define STM32_LPTIM5CLK STM32_PLL3_P_CK
+#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_LSE_CK
+#define STM32_LPTIM3CLK STM32_LSE_CK
+#define STM32_LPTIM4CLK STM32_LSE_CK
+#define STM32_LPTIM5CLK STM32_LSE_CK
+#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_LSI_CK
+#define STM32_LPTIM3CLK STM32_LSI_CK
+#define STM32_LPTIM4CLK STM32_LSI_CK
+#define STM32_LPTIM5CLK STM32_LSI_CK
+#elif STM32_LPTIM345SEL == STM32_LPTIM345SEL_PER_CK
+#define STM32_LPTIM3CLK STM32_PER_CK
+#define STM32_LPTIM4CLK STM32_PER_CK
+#define STM32_LPTIM5CLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_LPTIM345SEL clock"
+#endif
+
+#if !defined(STM32H723xx)
+#if (STM32_USART16SEL == STM32_USART16SEL_PCLK2) || defined(__DOXYGEN__)
+/**
+ * @brief USART1 clock.
+ */
+#define STM32_USART1CLK STM32_PCLK2
+
+/**
+ * @brief USART6 clock.
+ */
+#define STM32_USART6CLK STM32_PCLK2
+
+#elif STM32_USART16SEL == STM32_USART16SEL_PLL2_Q_CK
+#define STM32_USART1CLK STM32_PLL2_Q_CK
+#define STM32_USART6CLK STM32_PLL2_Q_CK
+#elif STM32_USART16SEL == STM32_USART16SEL_PLL3_Q_CK
+#define STM32_USART1CLK STM32_PLL3_Q_CK
+#define STM32_USART6CLK STM32_PLL3_Q_CK
+#elif STM32_USART16SEL == STM32_USART16SEL_HSI_KER_CK
+#define STM32_USART1CLK STM32_HSI_CK
+#define STM32_USART6CLK STM32_HSI_CK
+#elif STM32_USART16SEL == STM32_USART16SEL_CSI_KER_CK
+#define STM32_USART1CLK STM32_CSI_CK
+#define STM32_USART6CLK STM32_CSI_CK
+#elif STM32_USART16SEL == STM32_USART16SEL_LSE_CK
+#define STM32_USART1CLK STM32_LSE_CK
+#define STM32_USART6CLK STM32_LSE_CK
+#else
+#error "invalid source selected for STM32_USART16SEL clock"
+#endif
+#else // then defined(STM32H723xx)
+#if (STM32_USART16910SEL == STM32_USART16910SEL_PCLK2) || defined(__DOXYGEN__)
+
+#define STM32_USART1CLK STM32_PCLK2
+#define STM32_USART6CLK STM32_PCLK2
+#define STM32_USART9CLK STM32_PCLK2
+#define STM32_USART10CLK STM32_PCLK2
+
+#elif STM32_USART16910SEL == STM32_USART16910SEL_PLL2_Q_CK
+#define STM32_USART1CLK STM32_PLL2_Q_CK
+#define STM32_USART6CLK STM32_PLL2_Q_CK
+#define STM32_USART9CLK STM32_PLL2_Q_CK
+#define STM32_USART10CLK STM32_PLL2_Q_CK
+#elif STM32_USART16910SEL == STM32_USART16910SEL_PLL3_Q_CK
+#define STM32_USART1CLK STM32_PLL3_Q_CK
+#define STM32_USART6CLK STM32_PLL3_Q_CK
+#define STM32_USART9CLK STM32_PLL3_Q_CK
+#define STM32_USART10CLK STM32_PLL3_Q_CK
+#elif STM32_USART16910SEL == STM32_USART16910SEL_HSI_KER_CK
+#define STM32_USART1CLK STM32_HSI_CK
+#define STM32_USART6CLK STM32_HSI_CK
+#define STM32_USART9CLK STM32_HSI_CK
+#define STM32_USART10CLK STM32_HSI_CK
+#elif STM32_USART16910SEL == STM32_USART16910SEL_CSI_KER_CK
+#define STM32_USART1CLK STM32_CSI_CK
+#define STM32_USART6CLK STM32_CSI_CK
+#define STM32_USART9CLK STM32_CSI_CK
+#define STM32_USART10CLK STM32_CSI_CK
+#elif STM32_USART16910SEL == STM32_USART16910SEL_LSE_CK
+#define STM32_USART1CLK STM32_LSE_CK
+#define STM32_USART6CLK STM32_LSE_CK
+#define STM32_USART9CLK STM32_LSE_CK
+#define STM32_USART10CLK STM32_LSE_CK
+#else
+#error "invalid source selected for STM32_USART16910SEL clock"
+#endif
+#endif // !defined(STM32H723xx)
+
+#if (STM32_USART234578SEL == STM32_USART234578SEL_PCLK1) || defined(__DOXYGEN__)
+/**
+ * @brief USART2 clock.
+ */
+#define STM32_USART2CLK STM32_PCLK1
+
+/**
+ * @brief USART3 clock.
+ */
+#define STM32_USART3CLK STM32_PCLK1
+
+/**
+ * @brief USART4 clock.
+ */
+#define STM32_UART4CLK STM32_PCLK1
+
+/**
+ * @brief USART5 clock.
+ */
+#define STM32_UART5CLK STM32_PCLK1
+
+/**
+ * @brief USART7 clock.
+ */
+#define STM32_UART7CLK STM32_PCLK1
+
+/**
+ * @brief USART8 clock.
+ */
+#define STM32_UART8CLK STM32_PCLK1
+
+#elif STM32_USART234578SEL == STM32_USART234578SEL_PLL2_Q_CK
+#define STM32_USART2CLK STM32_PLL2_Q_CK
+#define STM32_USART3CLK STM32_PLL2_Q_CK
+#define STM32_UART4CLK STM32_PLL2_Q_CK
+#define STM32_UART5CLK STM32_PLL2_Q_CK
+#define STM32_UART7CLK STM32_PLL2_Q_CK
+#define STM32_UART8CLK STM32_PLL2_Q_CK
+#elif STM32_USART234578SEL == STM32_USART234578SEL_PLL3_Q_CK
+#define STM32_USART2CLK STM32_PLL3_Q_CK
+#define STM32_USART3CLK STM32_PLL3_Q_CK
+#define STM32_UART4CLK STM32_PLL3_Q_CK
+#define STM32_UART5CLK STM32_PLL3_Q_CK
+#define STM32_UART7CLK STM32_PLL3_Q_CK
+#define STM32_UART8CLK STM32_PLL3_Q_CK
+#elif STM32_USART234578SEL == STM32_USART234578SEL_HSI_KER_CK
+#define STM32_USART2CLK STM32_HSI_CK
+#define STM32_USART3CLK STM32_HSI_CK
+#define STM32_UART4CLK STM32_HSI_CK
+#define STM32_UART5CLK STM32_HSI_CK
+#define STM32_UART7CLK STM32_HSI_CK
+#define STM32_UART8CLK STM32_HSI_CK
+#elif STM32_USART234578SEL == STM32_USART234578SEL_CSI_KER_CK
+#define STM32_USART2CLK STM32_CSI_CK
+#define STM32_USART3CLK STM32_CSI_CK
+#define STM32_UART4CLK STM32_CSI_CK
+#define STM32_UART5CLK STM32_CSI_CK
+#define STM32_UART7CLK STM32_CSI_CK
+#define STM32_UART8CLK STM32_CSI_CK
+#elif STM32_USART234578SEL == STM32_USART234578SEL_LSE_CK
+#define STM32_USART2CLK STM32_LSE_CK
+#define STM32_USART3CLK STM32_LSE_CK
+#define STM32_UART4CLK STM32_LSE_CK
+#define STM32_UART6CLK STM32_LSE_CK
+#define STM32_UART7CLK STM32_LSE_CK
+#define STM32_UART8CLK STM32_LSE_CK
+#else
+#error "invalid source selected for STM32_USART234578SEL clock"
+#endif
+
+#if (STM32_LPUART1SEL == STM32_LPUART1SEL_PCLK4) || defined(__DOXYGEN__)
+/**
+ * @brief LPUART1 clock.
+ */
+#define STM32_LPUART1CLK STM32_PCLK4
+
+#elif STM32_LPUART1SEL == STM32_LPUART1SEL_PLL2_Q_CK
+#define STM32_LPUART1CLK STM32_PLL2_Q_CK
+#elif STM32_LPUART1SEL == STM32_LPUART1SEL_PLL3_Q_CK
+#define STM32_LPUART1CLK STM32_PLL3_Q_CK
+#elif STM32_LPUART1SEL == STM32_LPUART1SEL_HSI_KER_CK
+#define STM32_LPUART1CLK STM32_HSI_CK
+#elif STM32_LPUART1SEL == STM32_LPUART1SEL_CSI_KER_CK
+#define STM32_LPUART1CLK STM32_CSI_CK
+#elif STM32_LPUART1SEL == STM32_LPUART1SEL_LSE_CK
+#define STM32_LPUART1CLK STM32_LSE_CK
+#else
+#error "invalid source selected for STM32_LPUART1SEL clock"
+#endif
+
+#if (STM32_SPI123SEL == STM32_SPI123SEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SPI1 clock.
+ */
+#define STM32_SPI1CLK STM32_PLL1_Q_CK
+
+/**
+ * @brief SPI2 clock.
+ */
+#define STM32_SPI2CLK STM32_PLL1_Q_CK
+
+/**
+ * @brief SPI3 clock.
+ */
+#define STM32_SPI3CLK STM32_PLL1_Q_CK
+#elif STM32_SPI123SEL == STM32_SPI123SEL_PLL2_P_CK
+#define STM32_SPI1CLK STM32_PLL2_P_CK
+#define STM32_SPI2CLK STM32_PLL2_P_CK
+#define STM32_SPI3CLK STM32_PLL2_P_CK
+#elif STM32_SPI123SEL == STM32_SPI123SEL_PLL3_P_CK
+#define STM32_SPI1CLK STM32_PLL3_P_CK
+#define STM32_SPI2CLK STM32_PLL3_P_CK
+#define STM32_SPI3CLK STM32_PLL3_P_CK
+#elif STM32_SPI123SEL == STM32_SPI123SEL_I2S_CKIN
+#define STM32_SPI1CLK 0 /* Unknown, would require a board value */
+#define STM32_SPI2CLK 0 /* Unknown, would require a board value */
+#define STM32_SPI3CLK 0 /* Unknown, would require a board value */
+#elif STM32_SPI123SEL == STM32_SPI123SEL_PER_CK
+#define STM32_SPI1CLK STM32_PER_CK
+#define STM32_SPI2CLK STM32_PER_CK
+#define STM32_SPI3CLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_SPI123SEL clock"
+#endif
+
+#if (STM32_SPI45SEL == STM32_SPI45SEL_PCLK2) || defined(__DOXYGEN__)
+/**
+ * @brief SPI4 clock.
+ */
+#define STM32_SPI4CLK STM32_PCLK2
+
+/**
+ * @brief SPI5 clock.
+ */
+#define STM32_SPI5CLK STM32_PCLK2
+
+#elif STM32_SPI45SEL == STM32_SPI45SEL_PLL2_Q_CK
+#define STM32_SPI4CLK STM32_PLL2_Q_CK
+#define STM32_SPI5CLK STM32_PLL2_Q_CK
+#elif STM32_SPI45SEL == STM32_SPI45SEL_PLL3_Q_CK
+#define STM32_SPI4CLK STM32_PLL3_Q_CK
+#define STM32_SPI5CLK STM32_PLL3_Q_CK
+#elif STM32_SPI45SEL == STM32_SPI45SEL_HSI_KER_CK
+#define STM32_SPI4CLK STM32_HSI_CK
+#define STM32_SPI5CLK STM32_HSI_CK
+#elif STM32_SPI45SEL == STM32_SPI45SEL_CSI_KER_CK
+#define STM32_SPI4CLK STM32_CSI_CK
+#define STM32_SPI5CLK STM32_CSI_CK
+#elif STM32_SPI45SEL == STM32_SPI45SEL_HSE_CK
+#define STM32_SPI4CLK STM32_HSE_CK
+#define STM32_SPI5CLK STM32_HSE_CK
+#else
+#error "invalid source selected for STM32_SPI45SEL clock"
+#endif
+
+#if (STM32_SPI6SEL == STM32_SPI6SEL_PCLK4) || defined(__DOXYGEN__)
+/**
+ * @brief SPI6 clock.
+ */
+#define STM32_SPI6CLK STM32_PCLK4
+
+#elif STM32_SPI6SEL == STM32_SPI6SEL_PLL2_Q_CK
+#define STM32_SPI6CLK STM32_PLL2_Q_CK
+#elif STM32_SPI6SEL == STM32_SPI6SEL_PLL3_Q_CK
+#define STM32_SPI6CLK STM32_PLL3_Q_CK
+#elif STM32_SPI6SEL == STM32_SPI6SEL_HSI_KER_CK
+#define STM32_SPI6CLK STM32_HSI_CK
+#elif STM32_SPI6SEL == STM32_SPI6SEL_CSI_KER_CK
+#define STM32_SPI6CLK STM32_CSI_CK
+#elif STM32_SPI6SEL == STM32_SPI6SEL_HSE_CK
+#define STM32_SPI6CLK STM32_HSE_CK
+#else
+#error "invalid source selected for STM32_SPI6SEL clock"
+#endif
+
+#if !defined(STM32H723xx)
+#if (STM32_I2C123SEL == STM32_I2C123SEL_PCLK1) || defined(__DOXYGEN__)
+/**
+ * @brief I2C1 clock.
+ */
+#define STM32_I2C1CLK STM32_PCLK1
+
+/**
+ * @brief I2C2 clock.
+ */
+#define STM32_I2C2CLK STM32_PCLK1
+
+/**
+ * @brief I2C3 clock.
+ */
+#define STM32_I2C3CLK STM32_PCLK1
+
+#elif STM32_I2C123SEL == STM32_I2C123SEL_PLL3_R_CK
+#define STM32_I2C1CLK STM32_PLL3_R_CK
+#define STM32_I2C2CLK STM32_PLL3_R_CK
+#define STM32_I2C2CLK STM32_PLL3_R_CK
+
+#elif STM32_I2C123SEL == STM32_I2C123SEL_HSI_KER_CK
+#define STM32_I2C1CLK STM32_HSI_CK
+#define STM32_I2C2CLK STM32_HSI_CK
+#define STM32_I2C2CLK STM32_HSI_CK
+
+#elif STM32_I2C123SEL == STM32_I2C123SEL_CSI_KER_CK
+#define STM32_I2C1CLK STM32_CSI_CK
+#define STM32_I2C2CLK STM32_CSI_CK
+#define STM32_I2C2CLK STM32_CSI_CK
+#else
+#error "invalid source selected for STM32_I2C123SEL clock"
+#endif
+#else // then defined(STM32H723xx)
+#if (STM32_I2C1235SEL == STM32_I2C1235SEL_PCLK1) || defined(__DOXYGEN__)
+
+#define STM32_I2C1CLK STM32_PCLK1
+#define STM32_I2C2CLK STM32_PCLK1
+#define STM32_I2C3CLK STM32_PCLK1
+#define STM32_I2C5CLK STM32_PCLK1
+
+#elif STM32_I2C1235SEL == STM32_I2C1235SEL_PLL3_R_CK
+#define STM32_I2C1CLK STM32_PLL3_R_CK
+#define STM32_I2C2CLK STM32_PLL3_R_CK
+#define STM32_I2C3CLK STM32_PLL3_R_CK
+#define STM32_I2C5CLK STM32_PLL3_R_CK
+
+#elif STM32_I2C1235SEL == STM32_I2C1235SEL_HSI_KER_CK
+#define STM32_I2C1CLK STM32_HSI_CK
+#define STM32_I2C2CLK STM32_HSI_CK
+#define STM32_I2C3CLK STM32_HSI_CK
+#define STM32_I2C5CLK STM32_HSI_CK
+
+#elif STM32_I2C1235SEL == STM32_I2C1235SEL_CSI_KER_CK
+#define STM32_I2C1CLK STM32_CSI_CK
+#define STM32_I2C2CLK STM32_CSI_CK
+#define STM32_I2C3CLK STM32_CSI_CK
+#define STM32_I2C5CLK STM32_CSI_CK
+#else
+#error "invalid source selected for STM32_I2C1235SEL clock"
+#endif
+#endif // !defined(STM32H723xx)
+
+#if (STM32_I2C4SEL == STM32_I2C4SEL_PCLK4) || defined(__DOXYGEN__)
+/**
+ * @brief I2C1 clock.
+ */
+#define STM32_I2C4CLK STM32_PCLK4
+
+#elif STM32_I2C4SEL == STM32_I2C4SEL_PLL3_R_CK
+#define STM32_I2C4CLK STM32_PLL3_R_CK
+#elif STM32_I2C4SEL == STM32_I2C4SEL_HSI_KER_CK
+#define STM32_I2C4CLK STM32_HSI_CK
+#elif STM32_I2C4SEL == STM32_I2C4SEL_CSI_KER_CK
+#define STM32_I2C4CLK STM32_CSI_CK
+#else
+#error "invalid source selected for STM32_I2C4SEL clock"
+#endif
+
+#if (STM32_SAI1SEL == STM32_SAI1SEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SAI1 clock.
+ */
+#define STM32_SAI1CLK STM32_PLL1_Q_CK
+
+#elif STM32_SAI1SEL == STM32_SAI1SEL_PLL2_P_CK
+#define STM32_SAI1CLK STM32_PLL2_P_CK
+#elif STM32_SAI1SEL == STM32_SAI1SEL_PLL3_P_CK
+#define STM32_SAI1CLK STM32_PLL3_P_CK
+#elif STM32_SAI1SEL == STM32_SAI1SEL_I2S_CKIN
+#define STM32_SAI1CLK 0 /* Unknown, would require a board value */
+#elif STM32_SAI1SEL == STM32_SAI1SEL_PER_CK
+#define STM32_SAI1CLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_SAI1SEL clock"
+#endif
+
+#if !defined(STM32H723xx)
+#if (STM32_SAI23SEL == STM32_SAI23SEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SAI2 clock.
+ */
+#define STM32_SAI2CLK STM32_PLL1_Q_CK
+
+/**
+ * @brief SAI3 clock.
+ */
+#define STM32_SAI3CLK STM32_PLL1_Q_CK
+
+#elif STM32_SAI23SEL == STM32_SAI23SEL_PLL2_P_CK
+#define STM32_SAI2CLK STM32_PLL2_P_CK
+#define STM32_SAI3CLK STM32_PLL2_P_CK
+#elif STM32_SAI23SEL == STM32_SAI23SEL_PLL3_P_CK
+#define STM32_SAI2CLK STM32_PLL3_P_CK
+#define STM32_SAI3CLK STM32_PLL3_P_CK
+#elif STM32_SAI23SEL == STM32_SAI23SEL_I2S_CKIN
+#define STM32_SAI2CLK 0 /* Unknown, would require a board value */
+#define STM32_SAI3CLK 0 /* Unknown, would require a board value */
+#elif STM32_SAI23SEL == STM32_SAI23SEL_PER_CK
+#define STM32_SAI2CLK STM32_PER_CK
+#define STM32_SAI3CLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_SAI23SEL clock"
+#endif
+#endif // !defined(STM32H723xx)
+
+#if (STM32_SAI4ASEL == STM32_SAI4ASEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SAI4A clock.
+ */
+#define STM32_SAI4ACLK STM32_PLL1_Q_CK
+
+#elif STM32_SAI4ASEL == STM32_SAI4ASEL_PLL2_P_CK
+#define STM32_SAI4ACLK STM32_PLL2_P_CK
+#elif STM32_SAI4ASEL == STM32_SAI4ASEL_PLL3_P_CK
+#define STM32_SAI4ACLK STM32_PLL3_P_CK
+#elif STM32_SAI4ASEL == STM32_SAI4ASEL_I2S_CKIN
+#define STM32_SAI4ACLK 0 /* Unknown, would require a board value */
+#elif STM32_SAI4ASEL == STM32_SAI4ASEL_PER_CK
+#define STM32_SAI4ACLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_SAI4ASEL clock"
+#endif
+
+#if (STM32_SAI4BSEL == STM32_SAI4BSEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SAI4B clock.
+ */
+#define STM32_SAI4BCLK STM32_PLL1_Q_CK
+
+#elif STM32_SAI4BSEL == STM32_SAI4BSEL_PLL2_P_CK
+#define STM32_SAI4BCLK STM32_PLL2_P_CK
+#elif STM32_SAI4BSEL == STM32_SAI4BSEL_PLL3_P_CK
+#define STM32_SAI4BCLK STM32_PLL3_P_CK
+#elif STM32_SAI4BSEL == STM32_SAI4BSEL_I2S_CKIN
+#define STM32_SAI4BCLK 0 /* Unknown, would require a board value */
+#elif STM32_SAI4BSEL == STM32_SAI4BSEL_PER_CK
+#define STM32_SAI4BCLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_SAI4BSEL clock"
+#endif
+
+#if (STM32_USBSEL == STM32_USBSEL_DISABLE) || defined(__DOXYGEN__)
+/**
+ * @brief USB clock.
+ */
+#define STM32_USBCLK 0
+
+#elif STM32_USBSEL == STM32_USBSEL_PLL1_Q_CK
+#define STM32_USBCLK STM32_PLL1_Q_CK
+#elif STM32_USBSEL == STM32_USBSEL_PLL3_Q_CK
+#define STM32_USBCLK STM32_PLL3_Q_CK
+#elif STM32_USBSEL == STM32_USBSEL_HSI48_CK
+#define STM32_USBCLK STM32_HSI48_CK
+#else
+#error "invalid source selected for STM32_USBSEL clock"
+#endif
+
+#if (STM32_SDMMCSEL == STM32_SDMMCSEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SDMMC1 frequency.
+ */
+#define STM32_SDMMC1CLK STM32_PLL1_Q_CK
+
+/**
+ * @brief SDMMC2 frequency.
+ */
+#define STM32_SDMMC2CLK STM32_PLL1_Q_CK
+
+#elif STM32_SDMMCSEL == STM32_SDMMCSEL_PLL2_R_CK
+#define STM32_SDMMC1CLK STM32_PLL2_R_CK
+#define STM32_SDMMC2CLK STM32_PLL2_R_CK
+#else
+#error "invalid source selected for STM32_SDMMCxSEL clock"
+#endif
+
+#if !defined(STM32H723xx)
+#if (STM32_QSPISEL == STM32_QSPISEL_HCLK) || defined(__DOXYGEN__)
+/**
+ * @brief QSPI frequency.
+ */
+#define STM32_QSPICLK STM32_HCLK
+
+#elif STM32_QSPISEL == STM32_QSPISEL_PLL1_Q_CK
+#define STM32_QSPICLK STM32_PLL1_Q_CK
+#elif STM32_QSPISEL == STM32_QSPISEL_PLL2_R_CK
+#define STM32_QSPICLK STM32_PLL2_R_CK
+#elif STM32_QSPISEL == STM32_QSPISEL_PER_CK
+#define STM32_QSPICLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_QSPISEL clock"
+#endif
+
+#if (STM32_FMCSEL == STM32_FMCSEL_HCLK) || defined(__DOXYGEN__)
+/**
+ * @brief FMC frequency.
+ */
+#define STM32_FMCCLK STM32_HCLK
+
+#elif STM32_FMCSEL == STM32_FMCSEL_PLL1_Q_CK
+#define STM32_FMCCLK STM32_PLL1_Q_CK
+#elif STM32_FMCSEL == STM32_FMCSEL_PLL2_R_CK
+#define STM32_FMCCLK STM32_PLL2_R_CK
+#elif STM32_FMCSEL == STM32_FMCSEL_PER_CK
+#define STM32_FMCCLK STM32_PER_CK
+#else
+#error "invalid source selected for STM32_FMCSEL clock"
+#endif
+#endif // !defined(STM32H723xx)
+
+#if (STM32_SWPSEL == STM32_SWPSEL_PCLK1) || defined(__DOXYGEN__)
+/**
+ * @brief SDMMC frequency.
+ */
+#define STM32_SWPCLK STM32_PCLK1
+
+#elif STM32_SWPSEL == STM32_SWPSEL_HSI_KER_CK
+#define STM32_SWPCLK STM32_HSI_CK
+#else
+#error "invalid source selected for STM32_SWPSEL clock"
+#endif
+
+#if (STM32_FDCANSEL == STM32_FDCANSEL_HSE_CK) || defined(__DOXYGEN__)
+/**
+ * @brief FDCAN frequency.
+ */
+#define STM32_FDCANCLK STM32_HSE_CK
+
+#elif STM32_FDCANSEL == STM32_FDCANSEL_PLL1_Q_CK
+#define STM32_FDCANCLK STM32_PLL1_Q_CK
+#elif STM32_FDCANSEL == STM32_FDCANSEL_PLL2_Q_CK
+#define STM32_FDCANCLK STM32_PLL2_Q_CK
+#else
+#error "invalid source selected for STM32_FDCANSEL clock"
+#endif
+
+#if (STM32_DFSDM1SEL == STM32_DFSDM1SEL_PCLK2) || defined(__DOXYGEN__)
+/**
+ * @brief SDMMC frequency.
+ */
+#define STM32_DFSDM1CLK STM32_PCLK2
+
+#elif STM32_DFSDM1SEL == STM32_DFSDM1SEL_SYS_CK
+#define STM32_DFSDM1CLK STM32_SYS_CK
+#else
+#error "invalid source selected for STM32_DFSDM1SEL clock"
+#endif
+
+#if (STM32_SPDIFSEL == STM32_SPDIFSEL_PLL1_Q_CK) || defined(__DOXYGEN__)
+/**
+ * @brief SPDIF frequency.
+ */
+#define STM32_SPDIFCLK STM32_PLL1_Q_CK
+
+#elif STM32_SPDIFSEL == STM32_SPDIFSEL_PLL2_R_CK
+#define STM32_SPDIFCLK STM32_PLL2_R_CK
+#elif STM32_SPDIFSEL == STM32_SPDIFSEL_PLL3_R_CK
+#define STM32_SPDIFCLK STM32_PLL3_R_CK
+#elif STM32_SPDIFSEL == STM32_SPDIFSEL_HSI_KET_CLK
+#define STM32_SPDIFCLK STM32_HSI_CK
+#else
+#error "invalid source selected for STM32_SPDIFSEL clock"
+#endif
+
+#if (STM32_CECSEL == STM32_CECSEL_LSE_CK) || defined(__DOXYGEN__)
+/**
+ * @brief CEC frequency.
+ */
+#define STM32_CECCLK STM32_LSE_CK
+
+#elif STM32_CECSEL == STM32_CECSEL_LSI_CK
+#define STM32_CECCLK STM32_LSI_CK
+#elif STM32_CECSEL == STM32_CECSEL_CSI_KER_CK
+#define STM32_CECCLK STM32_CSI_CK
+#elif STM32_CECSEL == STM32_CECSEL_DISABLE
+#define STM32_CECCLK 0
+#else
+#error "invalid source selected for STM32_CECSEL clock"
+#endif
+
+#if (STM32_RNGSEL == STM32_RNGSEL_HSI48_CK) || defined(__DOXYGEN__)
+/**
+ * @brief RNG frequency.
+ */
+#define STM32_RNGCLK STM32_HSI48_CK
+
+#elif STM32_RNGSEL == STM32_RNGSEL_PLL1_Q_CK
+#define STM32_RNGCLK STM32_PLL1_Q_CK
+#elif STM32_RNGSEL == STM32_RNGSEL_LSE_CK
+#define STM32_RNGCLK STM32_LSE_CK
+#elif STM32_RNGSEL == STM32_RNGSEL_LSI_CK
+#define STM32_RNGCLK STM32_LSI_CK
+#else
+#error "invalid source selected for STM32_RNGSEL clock"
+#endif
+
+#if (STM32_ADCSEL == STM32_ADCSEL_PLL2_P_CK) || defined(__DOXYGEN__)
+/**
+ * @brief ADC frequency.
+ */
+#define STM32_ADCCLK STM32_PLL2_P_CK
+
+#elif STM32_ADCSEL == STM32_ADCSEL_PLL3_R_CK
+#define STM32_ADCCLK STM32_PLL3_R_CK
+#elif STM32_ADCSEL == STM32_ADCSEL_PER_CK
+#define STM32_ADCCLK STM32_PER_CK
+#elif STM32_ADCSEL == STM32_ADCSEL_DISABLE
+#define STM32_ADCCLK 0
+#else
+#error "invalid source selected for STM32_ADCSEL clock"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+/* Various helpers.*/
+#include "nvic.h"
+#include "cache.h"
+#include "mpu_v7m.h"
+#include "stm32_isr.h"
+#include "stm32_mdma.h"
+#include "stm32_dma.h"
+#include "stm32_bdma.h"
+#include "stm32_exti.h"
+#include "stm32_rcc.h"
+#include "stm32_tim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void hal_lld_init(void);
+ void stm32_clock_init(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_LLD_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk new file mode 100644 index 0000000..05c12ef --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/platform.mk @@ -0,0 +1,50 @@ +# Required platform files.
+PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \
+ $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx/stm32_isr.c \
+ $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx/hal_lld.c
+
+# Required include directories.
+PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \
+ $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx
+
+# Optional platform files.
+ifeq ($(USE_SMART_BUILD),yes)
+
+# Configuration files directory
+ifeq ($(HALCONFDIR),)
+ ifeq ($(CONFDIR),)
+ HALCONFDIR = .
+ else
+ HALCONFDIR := $(CONFDIR)
+ endif
+endif
+
+HALCONF := $(strip $(shell cat $(HALCONFDIR)/halconf.h | egrep -e "\#define"))
+
+else
+endif
+
+# Drivers compatible with the platform.
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv4/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/BDMAv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/CRYPv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/FDCANv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv3/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/MDMAv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv2/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/SDMMCv2/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv3/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/RNGv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/driver.mk
+include $(CHIBIOS)/os/hal/ports/STM32/LLD/xWDGv1/driver.mk
+
+# Shared variables
+ALLCSRC += $(PLATFORMSRC)
+ALLINC += $(PLATFORMINC)
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h new file mode 100644 index 0000000..c4bace0 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_dmamux.h @@ -0,0 +1,206 @@ +/*
+ 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 STM32H7xx/stm32_dmamux.h
+ * @brief STM32H7xx DMAMUX handler header.
+ *
+ * @addtogroup STM32H7xx_DMAMUX
+ * @{
+ */
+
+#ifndef STM32_DMAMUX_H
+#define STM32_DMAMUX_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name DMAMUX1 request sources
+ * @{
+ */
+#define STM32_DMAMUX1_REQ_GEN0 1
+#define STM32_DMAMUX1_REQ_GEN1 2
+#define STM32_DMAMUX1_REQ_GEN2 3
+#define STM32_DMAMUX1_REQ_GEN3 4
+#define STM32_DMAMUX1_REQ_GEN4 5
+#define STM32_DMAMUX1_REQ_GEN5 6
+#define STM32_DMAMUX1_REQ_GEN6 7
+#define STM32_DMAMUX1_REQ_GEN7 8
+#define STM32_DMAMUX1_ADC1 9
+#define STM32_DMAMUX1_ADC2 10
+#define STM32_DMAMUX1_TIM1_CH1 11
+#define STM32_DMAMUX1_TIM1_CH2 12
+#define STM32_DMAMUX1_TIM1_CH3 13
+#define STM32_DMAMUX1_TIM1_CH4 14
+#define STM32_DMAMUX1_TIM1_UP 15
+#define STM32_DMAMUX1_TIM1_TRIG 16
+#define STM32_DMAMUX1_TIM1_COM 17
+#define STM32_DMAMUX1_TIM2_CH1 18
+#define STM32_DMAMUX1_TIM2_CH2 19
+#define STM32_DMAMUX1_TIM2_CH3 20
+#define STM32_DMAMUX1_TIM2_CH4 21
+#define STM32_DMAMUX1_TIM2_UP 22
+#define STM32_DMAMUX1_TIM3_CH1 23
+#define STM32_DMAMUX1_TIM3_CH2 24
+#define STM32_DMAMUX1_TIM3_CH3 25
+#define STM32_DMAMUX1_TIM3_CH4 26
+#define STM32_DMAMUX1_TIM3_UP 27
+#define STM32_DMAMUX1_TIM3_TRIG 28
+#define STM32_DMAMUX1_TIM4_CH1 29
+#define STM32_DMAMUX1_TIM4_CH2 30
+#define STM32_DMAMUX1_TIM4_CH3 31
+#define STM32_DMAMUX1_TIM4_UP 32
+#define STM32_DMAMUX1_I2C1_RX 33
+#define STM32_DMAMUX1_I2C1_TX 34
+#define STM32_DMAMUX1_I2C2_RX 35
+#define STM32_DMAMUX1_I2C2_TX 36
+#define STM32_DMAMUX1_SPI1_RX 37
+#define STM32_DMAMUX1_SPI1_TX 38
+#define STM32_DMAMUX1_SPI2_RX 39
+#define STM32_DMAMUX1_SPI2_TX 40
+#define STM32_DMAMUX1_USART1_RX 41
+#define STM32_DMAMUX1_USART1_TX 42
+#define STM32_DMAMUX1_USART2_RX 43
+#define STM32_DMAMUX1_USART2_TX 44
+#define STM32_DMAMUX1_USART3_RX 45
+#define STM32_DMAMUX1_USART3_TX 46
+#define STM32_DMAMUX1_TIM8_CH1 47
+#define STM32_DMAMUX1_TIM8_CH2 48
+#define STM32_DMAMUX1_TIM8_CH3 49
+#define STM32_DMAMUX1_TIM8_CH4 50
+#define STM32_DMAMUX1_TIM8_UP 51
+#define STM32_DMAMUX1_TIM8_TRIG 52
+#define STM32_DMAMUX1_TIM8_COM 53
+#define STM32_DMAMUX1_RESERVED54 54
+#define STM32_DMAMUX1_TIM5_CH1 55
+#define STM32_DMAMUX1_TIM5_CH2 56
+#define STM32_DMAMUX1_TIM5_CH3 57
+#define STM32_DMAMUX1_TIM5_CH4 58
+#define STM32_DMAMUX1_TIM5_UP 59
+#define STM32_DMAMUX1_TIM5_TRIG 60
+#define STM32_DMAMUX1_SPI3_RX 61
+#define STM32_DMAMUX1_SPI3_TX 62
+#define STM32_DMAMUX1_UART4_RX 63
+#define STM32_DMAMUX1_UART4_TX 64
+#define STM32_DMAMUX1_UART5_RX 65
+#define STM32_DMAMUX1_UART5_TX 66
+#define STM32_DMAMUX1_DAC1_CH1 67 /* Renamed to L4 name.*/
+#define STM32_DMAMUX1_DAC1_CH2 68 /* Renamed to L4 name.*/
+#define STM32_DMAMUX1_TIM6_UP 69
+#define STM32_DMAMUX1_TIM7_UP 70
+#define STM32_DMAMUX1_USART6_RX 71
+#define STM32_DMAMUX1_USART6_TX 72
+#define STM32_DMAMUX1_I2C3_RX 73
+#define STM32_DMAMUX1_I2C3_TX 74
+#define STM32_DMAMUX1_DCMI 75
+#define STM32_DMAMUX1_CRYP_IN 76
+#define STM32_DMAMUX1_CRYP_OUT 77
+#define STM32_DMAMUX1_HASH_IN 78
+#define STM32_DMAMUX1_UART7_RX 79
+#define STM32_DMAMUX1_UART7_TX 80
+#define STM32_DMAMUX1_UART8_RX 81
+#define STM32_DMAMUX1_UART8_TX 82
+#define STM32_DMAMUX1_SPI4_RX 83
+#define STM32_DMAMUX1_SPI4_TX 84
+#define STM32_DMAMUX1_SPI5_RX 85
+#define STM32_DMAMUX1_SPI5_TX 86
+#define STM32_DMAMUX1_SAI1_A 87
+#define STM32_DMAMUX1_SAI1_B 88
+#define STM32_DMAMUX1_SAI2_A 89
+#define STM32_DMAMUX1_SAI2_B 90
+#define STM32_DMAMUX1_SWPMI_RX 91
+#define STM32_DMAMUX1_SQPMI_TX 92
+#define STM32_DMAMUX1_SPDIFRX_DT 93
+#define STM32_DMAMUX1_SPDIFRX_CS 94
+#define STM32_DMAMUX1_HR_REQ1 95
+#define STM32_DMAMUX1_HR_REQ2 96
+#define STM32_DMAMUX1_HR_REQ3 97
+#define STM32_DMAMUX1_HR_REQ4 98
+#define STM32_DMAMUX1_HR_REQ5 99
+#define STM32_DMAMUX1_HR_REQ6 100
+#define STM32_DMAMUX1_DFSDM1_DMA0 101
+#define STM32_DMAMUX1_DFSDM1_DMA1 102
+#define STM32_DMAMUX1_DFSDM1_DMA2 103
+#define STM32_DMAMUX1_DFSDM1_DMA3 104
+#define STM32_DMAMUX1_TIM15_CH1 105
+#define STM32_DMAMUX1_TIM15_UP 106
+#define STM32_DMAMUX1_TIM15_TRIG 107
+#define STM32_DMAMUX1_TIM15_COM 108
+#define STM32_DMAMUX1_TIM16_CH1 109
+#define STM32_DMAMUX1_TIM16_UP 110
+#define STM32_DMAMUX1_TIM17_CH1 111
+#define STM32_DMAMUX1_TIM17_UP 112
+#define STM32_DMAMUX1_SAI3A 113
+#define STM32_DMAMUX1_SAI3B 114
+#define STM32_DMAMUX1_ADC3 115
+/** @} */
+
+/**
+ * @name DMAMUX2 request sources
+ * @{
+ */
+#define STM32_DMAMUX2_REQ_GEN0 1
+#define STM32_DMAMUX2_REQ_GEN1 2
+#define STM32_DMAMUX2_REQ_GEN2 3
+#define STM32_DMAMUX2_REQ_GEN3 4
+#define STM32_DMAMUX2_REQ_GEN4 5
+#define STM32_DMAMUX2_REQ_GEN5 6
+#define STM32_DMAMUX2_REQ_GEN6 7
+#define STM32_DMAMUX2_REQ_GEN7 8
+#define STM32_DMAMUX2_LP_UART1_RX 9
+#define STM32_DMAMUX2_LP_UART1_TX 10
+#define STM32_DMAMUX2_SPI6_RX 11
+#define STM32_DMAMUX2_SPI6_TX 12
+#define STM32_DMAMUX2_I2C4_RX 13
+#define STM32_DMAMUX2_I2C4_TX 14
+#define STM32_DMAMUX2_SAI4A 15
+#define STM32_DMAMUX2_SAI4B 16
+#define STM32_DMAMUX2_ADC3_REQ 17
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_DMAMUX_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c new file mode 100644 index 0000000..8ed4d72 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.c @@ -0,0 +1,198 @@ +/*
+ 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 STM32H7xx/stm32_isr.c
+ * @brief STM32H7xx ISR handler code.
+ *
+ * @addtogroup STM32H7xx_ISR
+ * @{
+ */
+
+#include "hal.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define exti_serve_irq(pr, channel) { \
+ \
+ if ((pr) & (1U << (channel))) { \
+ _pal_isr_code(channel); \
+ } \
+}
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#include "stm32_exti0.inc"
+#include "stm32_exti1.inc"
+#include "stm32_exti2.inc"
+#include "stm32_exti3.inc"
+#include "stm32_exti4.inc"
+#include "stm32_exti5_9.inc"
+#include "stm32_exti10_15.inc"
+#include "stm32_exti16.inc"
+#include "stm32_exti17.inc"
+#include "stm32_exti18.inc"
+#include "stm32_exti19.inc"
+#include "stm32_exti20_21.inc"
+
+#include "stm32_fdcan1.inc"
+#include "stm32_fdcan2.inc"
+
+#include "stm32_quadspi1.inc"
+
+#include "stm32_sdmmc1.inc"
+#include "stm32_sdmmc2.inc"
+
+#include <stm32_usart1.inc>
+#include "stm32_usart2.inc"
+#include "stm32_usart3.inc"
+#include "stm32_uart4.inc"
+#include "stm32_uart5.inc"
+#include "stm32_usart6.inc"
+#include "stm32_uart7.inc"
+#include "stm32_uart8.inc"
+#include "stm32_lpuart1.inc"
+
+#include "stm32_tim1.inc"
+#include "stm32_tim2.inc"
+#include "stm32_tim3.inc"
+#include "stm32_tim4.inc"
+#include "stm32_tim5.inc"
+#include "stm32_tim6.inc"
+#include "stm32_tim7.inc"
+#include "stm32_tim8_12_13_14.inc"
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables IRQ sources.
+ *
+ * @notapi
+ */
+void irqInit(void) {
+
+ exti0_irq_init();
+ exti1_irq_init();
+ exti2_irq_init();
+ exti3_irq_init();
+ exti4_irq_init();
+ exti5_9_irq_init();
+ exti10_15_irq_init();
+ exti16_irq_init();
+ exti17_irq_init();
+ exti18_irq_init();
+ exti19_irq_init();
+ exti20_exti21_irq_init();
+
+ fdcan1_irq_init();
+ fdcan2_irq_init();
+
+ mdma_irq_init();
+
+ quadspi1_irq_init();
+
+ sdmmc1_irq_init();
+ sdmmc2_irq_init();
+
+ tim1_irq_init();
+ tim2_irq_init();
+ tim3_irq_init();
+ tim4_irq_init();
+ tim5_irq_init();
+ tim6_irq_init();
+ tim7_irq_init();
+ tim8_tim12_tim13_tim14_irq_init();
+
+ usart1_irq_init();
+ usart2_irq_init();
+ usart3_irq_init();
+ uart4_irq_init();
+ uart5_irq_init();
+ usart6_irq_init();
+ uart7_irq_init();
+ uart8_irq_init();
+ lpuart1_irq_init();
+}
+
+/**
+ * @brief Disables IRQ sources.
+ *
+ * @notapi
+ */
+void irqDeinit(void) {
+
+ exti0_irq_deinit();
+ exti1_irq_deinit();
+ exti2_irq_deinit();
+ exti3_irq_deinit();
+ exti4_irq_deinit();
+ exti5_9_irq_deinit();
+ exti10_15_irq_deinit();
+ exti16_irq_deinit();
+ exti17_irq_deinit();
+ exti18_irq_deinit();
+ exti19_irq_deinit();
+ exti20_exti21_irq_deinit();
+
+ fdcan1_irq_deinit();
+ fdcan2_irq_deinit();
+
+ mdma_irq_deinit();
+
+ quadspi1_irq_deinit();
+
+ sdmmc1_irq_deinit();
+ sdmmc2_irq_deinit();
+
+ tim1_irq_deinit();
+ tim2_irq_deinit();
+ tim3_irq_deinit();
+ tim4_irq_deinit();
+ tim5_irq_deinit();
+ tim6_irq_deinit();
+ tim7_irq_deinit();
+ tim8_tim12_tim13_tim14_irq_deinit();
+
+ usart1_irq_deinit();
+ usart2_irq_deinit();
+ usart3_irq_deinit();
+ uart4_irq_deinit();
+ uart5_irq_deinit();
+ usart6_irq_deinit();
+ uart7_irq_deinit();
+ uart8_irq_deinit();
+ lpuart1_irq_deinit();
+}
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h new file mode 100644 index 0000000..e9b776a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_isr.h @@ -0,0 +1,384 @@ +/*
+ 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 STM32H7xx/stm32_isr.h
+ * @brief STM32H7xx ISR handler header.
+ *
+ * @addtogroup STM32H7xx_ISR
+ * @{
+ */
+
+#ifndef STM32_ISR_H
+#define STM32_ISR_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name ISRs suppressed in standard drivers
+ * @{
+ */
+#define STM32_TIM1_SUPPRESS_ISR
+#define STM32_TIM2_SUPPRESS_ISR
+#define STM32_TIM3_SUPPRESS_ISR
+#define STM32_TIM4_SUPPRESS_ISR
+#define STM32_TIM5_SUPPRESS_ISR
+#define STM32_TIM6_SUPPRESS_ISR
+#define STM32_TIM7_SUPPRESS_ISR
+#define STM32_TIM8_SUPPRESS_ISR
+#define STM32_TIM12_SUPPRESS_ISR
+#define STM32_TIM13_SUPPRESS_ISR
+#define STM32_TIM14_SUPPRESS_ISR
+#define STM32_TIM15_SUPPRESS_ISR
+#define STM32_TIM16_SUPPRESS_ISR
+#define STM32_TIM17_SUPPRESS_ISR
+
+#define STM32_USART1_SUPPRESS_ISR
+#define STM32_USART2_SUPPRESS_ISR
+#define STM32_USART3_SUPPRESS_ISR
+#define STM32_UART4_SUPPRESS_ISR
+#define STM32_UART5_SUPPRESS_ISR
+#define STM32_USART6_SUPPRESS_ISR
+#define STM32_UART7_SUPPRESS_ISR
+#define STM32_UART8_SUPPRESS_ISR
+#define STM32_LPUART1_SUPPRESS_ISR
+/** @} */
+
+/**
+ * @name ISR names and numbers
+ * @{
+ */
+/*
+ * ADC units.
+ */
+#define STM32_ADC12_HANDLER Vector88
+#define STM32_ADC3_HANDLER Vector23C
+
+#define STM32_ADC12_NUMBER 18
+#define STM32_ADC3_NUMBER 127
+
+/*
+ * BDMA units.
+ */
+#define STM32_BDMA1_CH0_HANDLER Vector244
+#define STM32_BDMA1_CH1_HANDLER Vector248
+#define STM32_BDMA1_CH2_HANDLER Vector24C
+#define STM32_BDMA1_CH3_HANDLER Vector250
+#define STM32_BDMA1_CH4_HANDLER Vector254
+#define STM32_BDMA1_CH5_HANDLER Vector258
+#define STM32_BDMA1_CH6_HANDLER Vector25C
+#define STM32_BDMA1_CH7_HANDLER Vector260
+
+#define STM32_BDMA1_CH0_NUMBER 129
+#define STM32_BDMA1_CH1_NUMBER 130
+#define STM32_BDMA1_CH2_NUMBER 131
+#define STM32_BDMA1_CH3_NUMBER 132
+#define STM32_BDMA1_CH4_NUMBER 133
+#define STM32_BDMA1_CH5_NUMBER 134
+#define STM32_BDMA1_CH6_NUMBER 135
+#define STM32_BDMA1_CH7_NUMBER 136
+
+/*
+ * DMA units.
+ */
+#define STM32_DMA1_CH0_HANDLER Vector6C
+#define STM32_DMA1_CH1_HANDLER Vector70
+#define STM32_DMA1_CH2_HANDLER Vector74
+#define STM32_DMA1_CH3_HANDLER Vector78
+#define STM32_DMA1_CH4_HANDLER Vector7C
+#define STM32_DMA1_CH5_HANDLER Vector80
+#define STM32_DMA1_CH6_HANDLER Vector84
+#define STM32_DMA1_CH7_HANDLER VectorFC
+#define STM32_DMA2_CH0_HANDLER Vector120
+#define STM32_DMA2_CH1_HANDLER Vector124
+#define STM32_DMA2_CH2_HANDLER Vector128
+#define STM32_DMA2_CH3_HANDLER Vector12C
+#define STM32_DMA2_CH4_HANDLER Vector130
+#define STM32_DMA2_CH5_HANDLER Vector150
+#define STM32_DMA2_CH6_HANDLER Vector154
+#define STM32_DMA2_CH7_HANDLER Vector158
+
+#define STM32_DMA1_CH0_NUMBER 11
+#define STM32_DMA1_CH1_NUMBER 12
+#define STM32_DMA1_CH2_NUMBER 13
+#define STM32_DMA1_CH3_NUMBER 14
+#define STM32_DMA1_CH4_NUMBER 15
+#define STM32_DMA1_CH5_NUMBER 16
+#define STM32_DMA1_CH6_NUMBER 17
+#define STM32_DMA1_CH7_NUMBER 47
+#define STM32_DMA2_CH0_NUMBER 56
+#define STM32_DMA2_CH1_NUMBER 57
+#define STM32_DMA2_CH2_NUMBER 58
+#define STM32_DMA2_CH3_NUMBER 59
+#define STM32_DMA2_CH4_NUMBER 60
+#define STM32_DMA2_CH5_NUMBER 68
+#define STM32_DMA2_CH6_NUMBER 69
+#define STM32_DMA2_CH7_NUMBER 70
+
+/*
+ * MDMA units.
+ */
+#define STM32_MDMA_HANDLER Vector228
+
+#define STM32_MDMA_NUMBER 122
+
+/*
+ * ETH units.
+ */
+#define STM32_ETH_HANDLER Vector134
+
+#define STM32_ETH_NUMBER 61
+
+/*
+ * EXTI units.
+ */
+#define STM32_EXTI0_HANDLER Vector58
+#define STM32_EXTI1_HANDLER Vector5C
+#define STM32_EXTI2_HANDLER Vector60
+#define STM32_EXTI3_HANDLER Vector64
+#define STM32_EXTI4_HANDLER Vector68
+#define STM32_EXTI5_9_HANDLER Vector9C
+#define STM32_EXTI10_15_HANDLER VectorE0
+#define STM32_EXTI16_HANDLER Vector44 /* PVD */
+#define STM32_EXTI17_HANDLER VectorE4 /* RTC ALARM */
+#define STM32_EXTI18_HANDLER Vector48 /* RTC TAMP CSS */
+#define STM32_EXTI19_HANDLER Vector4C /* RTC WAKEUP */
+#define STM32_EXTI2021_HANDLER Vector264 /* COMP1 COMP2 */
+
+#define STM32_EXTI0_NUMBER 6
+#define STM32_EXTI1_NUMBER 7
+#define STM32_EXTI2_NUMBER 8
+#define STM32_EXTI3_NUMBER 9
+#define STM32_EXTI4_NUMBER 10
+#define STM32_EXTI5_9_NUMBER 23
+#define STM32_EXTI10_15_NUMBER 40
+#define STM32_EXTI16_NUMBER 1
+#define STM32_EXTI17_NUMBER 41
+#define STM32_EXTI18_NUMBER 42
+#define STM32_EXTI19_NUMBER 3
+#define STM32_EXTI2021_NUMBER 137
+
+/*
+ * FDCAN units.
+ */
+#define STM32_FDCAN1_IT0_HANDLER Vector8C
+#define STM32_FDCAN1_IT1_HANDLER Vector94
+#define STM32_FDCAN2_IT0_HANDLER Vector90
+#define STM32_FDCAN2_IT1_HANDLER Vector98
+
+#define STM32_FDCAN1_IT0_NUMBER 19
+#define STM32_FDCAN1_IT1_NUMBER 21
+#define STM32_FDCAN2_IT0_NUMBER 20
+#define STM32_FDCAN2_IT1_NUMBER 22
+
+/*
+ * I2C units.
+ */
+#define STM32_I2C1_EVENT_HANDLER VectorBC
+#define STM32_I2C1_ERROR_HANDLER VectorC0
+#define STM32_I2C2_EVENT_HANDLER VectorC4
+#define STM32_I2C2_ERROR_HANDLER VectorC8
+#define STM32_I2C3_EVENT_HANDLER Vector160
+#define STM32_I2C3_ERROR_HANDLER Vector164
+#define STM32_I2C4_EVENT_HANDLER Vector1BC
+#define STM32_I2C4_ERROR_HANDLER Vector1C0
+
+#define STM32_I2C1_EVENT_NUMBER 31
+#define STM32_I2C1_ERROR_NUMBER 32
+#define STM32_I2C2_EVENT_NUMBER 33
+#define STM32_I2C2_ERROR_NUMBER 34
+#define STM32_I2C3_EVENT_NUMBER 72
+#define STM32_I2C3_ERROR_NUMBER 73
+#define STM32_I2C4_EVENT_NUMBER 95
+#define STM32_I2C4_ERROR_NUMBER 96
+
+/*
+ * QUADSPI units.
+ */
+#define STM32_QUADSPI1_HANDLER Vector1B0
+
+#define STM32_QUADSPI1_NUMBER 92
+
+/*
+ * SDMMC units.
+ */
+#define STM32_SDMMC1_HANDLER Vector104
+#define STM32_SDMMC2_HANDLER Vector230
+
+#define STM32_SDMMC1_NUMBER 49
+#define STM32_SDMMC2_NUMBER 131
+
+/*
+ * SPI units.
+ */
+#define STM32_SPI1_HANDLER VectorCC
+#define STM32_SPI2_HANDLER VectorD0
+#define STM32_SPI3_HANDLER Vector10C
+#define STM32_SPI4_HANDLER Vector190
+#define STM32_SPI5_HANDLER Vector194
+#define STM32_SPI6_HANDLER Vector198
+
+#define STM32_SPI1_NUMBER 35
+#define STM32_SPI2_NUMBER 36
+#define STM32_SPI3_NUMBER 51
+#define STM32_SPI4_NUMBER 84
+#define STM32_SPI5_NUMBER 85
+#define STM32_SPI6_NUMBER 86
+
+/*
+ * TIM units.
+ */
+#define STM32_TIM1_BRK_HANDLER VectorA0
+#define STM32_TIM1_UP_HANDLER VectorA4
+#define STM32_TIM1_TRGCO_HANDLER VectorA8
+#define STM32_TIM1_CC_HANDLER VectorAC
+#define STM32_TIM2_HANDLER VectorB0
+#define STM32_TIM3_HANDLER VectorB4
+#define STM32_TIM4_HANDLER VectorB8
+#define STM32_TIM5_HANDLER Vector108
+#define STM32_TIM6_HANDLER Vector118
+#define STM32_TIM7_HANDLER Vector11C
+#define STM32_TIM8_BRK_TIM12_HANDLER VectorEC
+#define STM32_TIM8_UP_TIM13_HANDLER VectorF0
+#define STM32_TIM8_TRGCO_TIM14_HANDLER VectorF4
+#define STM32_TIM8_CC_HANDLER VectorF8
+#define STM32_TIM15_HANDLER Vector210
+#define STM32_TIM16_HANDLER Vector214
+#define STM32_TIM17_HANDLER Vector218
+
+#define STM32_TIM1_BRK_NUMBER 24
+#define STM32_TIM1_UP_NUMBER 25
+#define STM32_TIM1_TRGCO_NUMBER 26
+#define STM32_TIM1_CC_NUMBER 27
+#define STM32_TIM2_NUMBER 28
+#define STM32_TIM3_NUMBER 29
+#define STM32_TIM4_NUMBER 30
+#define STM32_TIM5_NUMBER 50
+#define STM32_TIM6_NUMBER 54
+#define STM32_TIM7_NUMBER 55
+#define STM32_TIM8_BRK_TIM12_NUMBER 43
+#define STM32_TIM8_UP_TIM13_NUMBER 44
+#define STM32_TIM8_TRGCO_TIM14_NUMBER 45
+#define STM32_TIM8_CC_NUMBER 46
+#define STM32_TIM15_NUMBER 116
+#define STM32_TIM16_NUMBER 117
+#define STM32_TIM17_NUMBER 118
+
+/*
+ * USART/UART units.
+ */
+#define STM32_USART1_HANDLER VectorD4
+#define STM32_USART2_HANDLER VectorD8
+#define STM32_USART3_HANDLER VectorDC
+#define STM32_UART4_HANDLER Vector110
+#define STM32_UART5_HANDLER Vector114
+#define STM32_USART6_HANDLER Vector15C
+#define STM32_UART7_HANDLER Vector188
+#define STM32_UART8_HANDLER Vector18C
+#define STM32_LPUART1_HANDLER Vector278
+
+#define STM32_USART1_NUMBER 37
+#define STM32_USART2_NUMBER 38
+#define STM32_USART3_NUMBER 39
+#define STM32_UART4_NUMBER 52
+#define STM32_UART5_NUMBER 53
+#define STM32_USART6_NUMBER 71
+#define STM32_UART7_NUMBER 82
+#define STM32_UART8_NUMBER 83
+#define STM32_LPUART1_NUMBER 142
+
+/*
+ * USB/OTG units.
+ */
+#define STM32_OTG1_HANDLER Vector1D4
+#define STM32_OTG1_EP1OUT_HANDLER Vector1C8
+#define STM32_OTG1_EP1IN_HANDLER Vector1CC
+#define STM32_OTG2_HANDLER Vector174
+#define STM32_OTG2_EP1OUT_HANDLER Vector168
+#define STM32_OTG2_EP1IN_HANDLER Vector16C
+
+#define STM32_OTG1_NUMBER 101
+#define STM32_OTG1_EP1OUT_NUMBER 98
+#define STM32_OTG1_EP1IN_NUMBER 99
+#define STM32_OTG2_NUMBER 77
+#define STM32_OTG2_EP1OUT_NUMBER 74
+#define STM32_OTG2_EP1IN_NUMBER 75
+
+/*
+ * LTDC units.
+ */
+#define STM32_LTDC_EV_HANDLER Vector1A0
+#define STM32_LTDC_ER_HANDLER Vector1A4
+
+#define STM32_LTDC_EV_NUMBER 88
+#define STM32_LTDC_ER_NUMBER 89
+
+/*
+ * DMA2D units.
+ */
+#define STM32_DMA2D_HANDLER Vector1A8
+
+#define STM32_DMA2D_NUMBER 90
+
+/*
+ * FSMC units.
+ */
+#define STM32_FSMC_HANDLER Vector100
+
+#define STM32_FSMC_NUMBER 48
+
+/*
+ * DCMI units.
+ */
+#define STM32_DCMI_HANDLER Vector178
+
+#define STM32_DCMI_NUMBER 78
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void irqInit(void);
+ void irqDeinit(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_ISR_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h new file mode 100644 index 0000000..91d1086 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_rcc.h @@ -0,0 +1,1834 @@ +/*
+ 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 STM32F7xx/stm32_rcc.h
+ * @brief RCC helper driver header.
+ * @note This file requires definitions from the ST header file
+ * @p stm32f7xx.h.
+ *
+ * @addtogroup STM32F7xx_RCC
+ * @{
+ */
+#ifndef STM32_RCC_H
+#define STM32_RCC_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Generic RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the clock of one or more peripheral on the APB1 bus.
+ *
+ * @param[in] mask APB1 peripherals mask, low set
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAPB1L(mask, lp) { \
+ RCC->APB1LENR |= (mask); \
+ if (lp) \
+ RCC->APB1LLPENR |= (mask); \
+ else \
+ RCC->APB1LLPENR &= ~(mask); \
+ (void)RCC->APB1LLPENR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the APB1 bus.
+ *
+ * @param[in] mask APB1 peripherals mask, high set
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAPB1H(mask, lp) { \
+ RCC->APB1HENR |= (mask); \
+ if (lp) \
+ RCC->APB1HLPENR |= (mask); \
+ else \
+ RCC->APB1HLPENR &= ~(mask); \
+ (void)RCC->APB1HLPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the APB1 bus.
+ *
+ * @param[in] mask APB1 peripherals mask, low set
+ *
+ * @api
+ */
+#define rccDisableAPB1L(mask) { \
+ RCC->APB1LENR &= ~(mask); \
+ RCC->APB1LLPENR &= ~(mask); \
+ (void)RCC->APB1LLPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the APB1 bus.
+ *
+ * @param[in] mask APB1 peripherals mask, high set
+ *
+ * @api
+ */
+#define rccDisableAPB1H(mask) { \
+ RCC->APB1HENR &= ~(mask); \
+ RCC->APB1HLPENR &= ~(mask); \
+ (void)RCC->APB1HLPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the APB1 bus.
+ *
+ * @param[in] mask APB1 peripherals mask, low set
+ *
+ * @api
+ */
+#define rccResetAPB1L(mask) { \
+ RCC->APB1LRSTR |= (mask); \
+ RCC->APB1LRSTR &= ~(mask); \
+ (void)RCC->APB1LRSTR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the APB1 bus.
+ *
+ * @param[in] mask APB1 peripherals mask, high set
+ *
+ * @api
+ */
+#define rccResetAPB1H(mask) { \
+ RCC->APB1HRSTR |= (mask); \
+ RCC->APB1HRSTR &= ~(mask); \
+ (void)RCC->APB1HRSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the APB2 bus.
+ *
+ * @param[in] mask APB2 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAPB2(mask, lp) { \
+ RCC->APB2ENR |= (mask); \
+ if (lp) \
+ RCC->APB2LPENR |= (mask); \
+ else \
+ RCC->APB2LPENR &= ~(mask); \
+ (void)RCC->APB2LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the APB2 bus.
+ *
+ * @param[in] mask APB2 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAPB2(mask) { \
+ RCC->APB2ENR &= ~(mask); \
+ RCC->APB2LPENR &= ~(mask); \
+ (void)RCC->APB2LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the APB2 bus.
+ *
+ * @param[in] mask APB2 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAPB2(mask) { \
+ RCC->APB2RSTR |= (mask); \
+ RCC->APB2RSTR &= ~(mask); \
+ (void)RCC->APB2RSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the APB3 bus.
+ *
+ * @param[in] mask APB3 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAPB3(mask, lp) { \
+ RCC->APB3ENR |= (mask); \
+ if (lp) \
+ RCC->APB3LPENR |= (mask); \
+ else \
+ RCC->APB3LPENR &= ~(mask); \
+ (void)RCC->APB3LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the APB3 bus.
+ *
+ * @param[in] mask APB3 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAPB3(mask) { \
+ RCC->APB3ENR &= ~(mask); \
+ RCC->APB3LPENR &= ~(mask); \
+ (void)RCC->APB3LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the APB3 bus.
+ *
+ * @param[in] mask APB2 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAPB3(mask) { \
+ RCC->APB3RSTR |= (mask); \
+ RCC->APB3RSTR &= ~(mask); \
+ (void)RCC->APB3RSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the APB4 bus.
+ *
+ * @param[in] mask APB4 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAPB4(mask, lp) { \
+ RCC->APB4ENR |= (mask); \
+ if (lp) \
+ RCC->APB4LPENR |= (mask); \
+ else \
+ RCC->APB4LPENR &= ~(mask); \
+ (void)RCC->APB4LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the APB4 bus.
+ *
+ * @param[in] mask APB4 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAPB4(mask) { \
+ RCC->APB4ENR &= ~(mask); \
+ RCC->APB4LPENR &= ~(mask); \
+ (void)RCC->APB4LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the APB4 bus.
+ *
+ * @param[in] mask APB4 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAPB4(mask) { \
+ RCC->APB4RSTR |= (mask); \
+ RCC->APB4RSTR &= ~(mask); \
+ (void)RCC->APB4RSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the AHB1 bus.
+ *
+ * @param[in] mask AHB1 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAHB1(mask, lp) { \
+ RCC->AHB1ENR |= (mask); \
+ if (lp) \
+ RCC->AHB1LPENR |= (mask); \
+ else \
+ RCC->AHB1LPENR &= ~(mask); \
+ (void)RCC->AHB1LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the AHB1 bus.
+ *
+ * @param[in] mask AHB1 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAHB1(mask) { \
+ RCC->AHB1ENR &= ~(mask); \
+ RCC->AHB1LPENR &= ~(mask); \
+ (void)RCC->AHB1LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the AHB1 bus.
+ *
+ * @param[in] mask AHB1 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAHB1(mask) { \
+ RCC->AHB1RSTR |= (mask); \
+ RCC->AHB1RSTR &= ~(mask); \
+ (void)RCC->AHB1RSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the AHB2 bus.
+ *
+ * @param[in] mask AHB2 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAHB2(mask, lp) { \
+ RCC->AHB2ENR |= (mask); \
+ if (lp) \
+ RCC->AHB2LPENR |= (mask); \
+ else \
+ RCC->AHB2LPENR &= ~(mask); \
+ (void)RCC->AHB2LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the AHB2 bus.
+ *
+ * @param[in] mask AHB2 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAHB2(mask) { \
+ RCC->AHB2ENR &= ~(mask); \
+ RCC->AHB2LPENR &= ~(mask); \
+ (void)RCC->AHB2LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the AHB2 bus.
+ *
+ * @param[in] mask AHB2 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAHB2(mask) { \
+ RCC->AHB2RSTR |= (mask); \
+ RCC->AHB2RSTR &= ~(mask); \
+ (void)RCC->AHB2RSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the AHB3 bus.
+ *
+ * @param[in] mask AHB3 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAHB3(mask, lp) { \
+ RCC->AHB3ENR |= (mask); \
+ if (lp) \
+ RCC->AHB3LPENR |= (mask); \
+ else \
+ RCC->AHB3LPENR &= ~(mask); \
+ (void)RCC->AHB3LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the AHB3 bus.
+ *
+ * @param[in] mask AHB3 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAHB3(mask) { \
+ RCC->AHB3ENR &= ~(mask); \
+ RCC->AHB3LPENR &= ~(mask); \
+ (void)RCC->AHB3LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the AHB3 bus.
+ *
+ * @param[in] mask AHB3 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAHB3(mask) { \
+ RCC->AHB3RSTR |= (mask); \
+ RCC->AHB3RSTR &= ~(mask); \
+ (void)RCC->AHB3RSTR; \
+}
+
+/**
+ * @brief Enables the clock of one or more peripheral on the AHB4 bus.
+ *
+ * @param[in] mask AHB4 peripherals mask
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableAHB4(mask, lp) { \
+ RCC->AHB4ENR |= (mask); \
+ if (lp) \
+ RCC->AHB4LPENR |= (mask); \
+ else \
+ RCC->AHB4LPENR &= ~(mask); \
+ (void)RCC->AHB4LPENR; \
+}
+
+/**
+ * @brief Disables the clock of one or more peripheral on the AHB4 bus.
+ *
+ * @param[in] mask AHB4 peripherals mask
+ *
+ * @api
+ */
+#define rccDisableAHB4(mask) { \
+ RCC->AHB4ENR &= ~(mask); \
+ RCC->AHB4LPENR &= ~(mask); \
+ (void)RCC->AHB4LPENR; \
+}
+
+/**
+ * @brief Resets one or more peripheral on the AHB4 bus.
+ *
+ * @param[in] mask AHB4 peripherals mask
+ *
+ * @api
+ */
+#define rccResetAHB4(mask) { \
+ RCC->AHB4RSTR |= (mask); \
+ RCC->AHB4RSTR &= ~(mask); \
+ (void)RCC->AHB4RSTR; \
+}
+/** @} */
+
+/**
+ * @name ADC peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the ADC1/ADC2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableADC12(lp) rccEnableAHB1(RCC_AHB1ENR_ADC12EN, lp)
+
+/**
+ * @brief Disables the ADC1/ADC2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableADC12() rccDisableAHB1(RCC_AHB1ENR_ADC12EN)
+
+/**
+ * @brief Resets the ADC1/ADC2 peripheral.
+ *
+ * @api
+ */
+#define rccResetADC12() rccResetAHB1(RCC_AHB1RSTR_ADC12RST)
+
+/**
+ * @brief Enables the ADC3 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableADC3(lp) rccEnableAHB4(RCC_AHB4ENR_ADC3EN, lp)
+
+/**
+ * @brief Disables the ADC3 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableADC3() rccDisableAHB4(RCC_AHB4ENR_ADC3EN)
+
+/**
+ * @brief Resets the ADC3 peripheral.
+ *
+ * @api
+ */
+#define rccResetADC3() rccResetAHB4(RCC_AHB4RSTR_ADC3RST)
+/** @} */
+
+/**
+ * @name DAC peripheral specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the DAC1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableDAC1(lp) rccEnableAPB1L(RCC_APB1LENR_DAC12EN, lp)
+
+/**
+ * @brief Disables the DAC1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableDAC1() rccDisableAPB1L(RCC_APB1LENR_DAC12EN)
+
+/**
+ * @brief Resets the DAC1 peripheral.
+ *
+ * @api
+ */
+#define rccResetDAC1() rccResetAPB1L(RCC_APB1LRSTR_DAC12RST)
+/** @} */
+
+/**
+ * @name DMA peripheral specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the BDMA1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableBDMA1(lp) rccEnableAHB4(RCC_AHB4ENR_BDMAEN, lp)
+
+/**
+ * @brief Disables the BDMA1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableBDMA1() rccDisableAHB4(RCC_AHB4ENR_BDMAEN)
+
+/**
+ * @brief Resets the BDMA1 peripheral.
+ *
+ * @api
+ */
+#define rccResetBDMA1() rccResetAHB4(RCC_AHB4RSTR_BDMARST)
+
+/**
+ * @brief Enables the DMA1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableDMA1(lp) rccEnableAHB1(RCC_AHB1ENR_DMA1EN, lp)
+
+/**
+ * @brief Disables the DMA1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableDMA1() rccDisableAHB1(RCC_AHB1ENR_DMA1EN)
+
+/**
+ * @brief Resets the DMA1 peripheral.
+ *
+ * @api
+ */
+#define rccResetDMA1() rccResetAHB1(RCC_AHB1RSTR_DMA1RST)
+
+/**
+ * @brief Enables the DMA2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableDMA2(lp) rccEnableAHB1(RCC_AHB1ENR_DMA2EN, lp)
+
+/**
+ * @brief Disables the DMA2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableDMA2() rccDisableAHB1(RCC_AHB1ENR_DMA2EN)
+
+/**
+ * @brief Resets the DMA2 peripheral.
+ *
+ * @api
+ */
+#define rccResetDMA2() rccResetAHB1(RCC_AHB1RSTR_DMA2RST)
+
+/**
+ * @brief Enables the MDMA peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableMDMA(lp) rccEnableAHB3(RCC_AHB3ENR_MDMAEN, lp)
+
+/**
+ * @brief Disables the MDMA peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableMDMA() rccDisableAHB3(RCC_AHB3ENR_MDMAEN)
+
+/**
+ * @brief Resets the MDMA peripheral.
+ *
+ * @api
+ */
+#define rccResetMDMA() rccResetAHB3(RCC_AHB3ENR_MDMARST)
+/** @} */
+
+/**
+ * @name RAM specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the BKPRAM clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableBKPRAM(lp) rccEnableAHB4(RCC_AHB4ENR_BKPRAMEN, lp)
+
+/**
+ * @brief Disables the BKPRAM clock.
+ *
+ * @api
+ */
+#define rccDisableBKPRAM() rccDisableAHB4(RCC_AHB4ENR_BKPRAMEN)
+
+/**
+ * @brief Enables the SRAM1 clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSRAM1(lp) rccEnableAHB2(RCC_AHB2ENR_D2SRAM1EN, lp)
+
+/**
+ * @brief Disables the SRAM1 clock.
+ *
+ * @api
+ */
+#define rccDisableSRAM1() rccDisableAHB2(RCC_AHB2ENR_D2SRAM1EN)
+
+/**
+ * @brief Enables the SRAM2 clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSRAM2(lp) rccEnableAHB2(RCC_AHB2ENR_D2SRAM2EN, lp)
+
+/**
+ * @brief Disables the SRAM2 clock.
+ *
+ * @api
+ */
+#define rccDisableSRAM2() rccDisableAHB2(RCC_AHB2ENR_D2SRAM2EN)
+
+#if !defined(STM32H723xx)
+/**
+ * @brief Enables the SRAM3 clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSRAM3(lp) rccEnableAHB2(RCC_AHB2ENR_D2SRAM3EN, lp)
+
+/**
+ * @brief Disables the SRAM3 clock.
+ *
+ * @api
+ */
+#define rccDisableSRAM3() rccDisableAHB2(RCC_AHB2ENR_D2SRAM3EN)
+#endif // !defined(STM32H723xx)
+/** @} */
+
+/**
+ * @name ETH peripheral specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the ETH peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableETH(lp) rccEnableAHB1(RCC_AHB1ENR_ETHMACEN | \
+ RCC_AHB1ENR_ETHMACTXEN | \
+ RCC_AHB1ENR_ETHMACRXEN, lp)
+
+/**
+ * @brief Disables the ETH peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableETH() rccDisableAHB1(RCC_AHB1ENR_ETHMACEN | \
+ RCC_AHB1ENR_ETHMACTXEN | \
+ RCC_AHB1ENR_ETHMACRXEN)
+
+/**
+ * @brief Resets the ETH peripheral.
+ *
+ * @api
+ */
+#define rccResetETH() rccResetAHB1(RCC_AHB1RSTR_ETHMACRST)
+/** @} */
+
+/**
+ * @name FDCAN peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the FDCAN peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableFDCAN(lp) rccEnableAPB1H(RCC_APB1HENR_FDCANEN, lp)
+
+/**
+ * @brief Disables the FDCAN peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableFDCAN() rccDisableAPB1H(RCC_APB1HENR_FDCANEN)
+
+/**
+ * @brief Resets the FDCAN peripheral.
+ *
+ * @api
+ */
+#define rccResetFDCAN() rccResetAPB1H(RCC_APB1HRSTR_FDCANRST)
+/** @} */
+
+/**
+ * @name I2C peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the I2C1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableI2C1(lp) rccEnableAPB1L(RCC_APB1LENR_I2C1EN, lp)
+
+/**
+ * @brief Disables the I2C1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableI2C1() rccDisableAPB1L(RCC_APB1LENR_I2C1EN)
+
+/**
+ * @brief Resets the I2C1 peripheral.
+ *
+ * @api
+ */
+#define rccResetI2C1() rccResetAPB1L(RCC_APB1LRSTR_I2C1RST)
+
+/**
+ * @brief Enables the I2C2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableI2C2(lp) rccEnableAPB1L(RCC_APB1LENR_I2C2EN, lp)
+
+/**
+ * @brief Disables the I2C2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableI2C2() rccDisableAPB1L(RCC_APB1LENR_I2C2EN)
+
+/**
+ * @brief Resets the I2C2 peripheral.
+ *
+ * @api
+ */
+#define rccResetI2C2() rccResetAPB1L(RCC_APB1LRSTR_I2C2RST)
+
+/**
+ * @brief Enables the I2C3 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableI2C3(lp) rccEnableAPB1L(RCC_APB1LENR_I2C3EN, lp)
+
+/**
+ * @brief Disables the I2C3 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableI2C3() rccDisableAPB1L(RCC_APB1LENR_I2C3EN)
+
+/**
+ * @brief Resets the I2C3 peripheral.
+ *
+ * @api
+ */
+#define rccResetI2C3() rccResetAPB1L(RCC_APB1LRSTR_I2C3RST)
+
+/**
+ * @brief Enables the I2C4 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableI2C4(lp) rccEnableAPB4(RCC_APB4ENR_I2C4EN, lp)
+
+/**
+ * @brief Disables the I2C4 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableI2C4() rccDisableAPB4(RCC_APB4ENR_I2C4EN)
+
+/**
+ * @brief Resets the I2C4 peripheral.
+ *
+ * @api
+ */
+#define rccResetI2C4() rccResetAPB4(RCC_APB4RSTR_I2C4RST)
+/** @} */
+
+/**
+ * @name OTG peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the USB1_OTG_HS peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSB1_OTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_USB1OTGHSEN, lp)
+
+/**
+ * @brief Disables the USB1_OTG_HS peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSB1_OTG_HS() rccDisableAHB1(RCC_AHB1ENR_USB1OTGHSEN)
+
+/**
+ * @brief Resets the USB1_OTG_HS peripheral.
+ *
+ * @api
+ */
+#define rccResetUSB1_OTG_HS() rccResetAHB1(RCC_AHB1RSTR_USB1OTGHSRST)
+
+#if !defined(STM32H723xx)
+
+/**
+ * @brief Enables the USB2_OTG_HS peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSB2_OTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_USB2OTGHSEN, lp)
+
+/**
+ * @brief Disables the USB2_OTG_HS peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSB2_OTG_HS() rccDisableAHB1(RCC_AHB1ENR_USB2OTGHSEN)
+
+/**
+ * @brief Resets the USB2_OTG_HS peripheral.
+ *
+ * @api
+ */
+#define rccResetUSB2_OTG_HS() rccResetAHB1(RCC_AHB1RSTR_USB2OTGHSRST)
+
+#endif // !defined(STM32H723xx)
+
+/**
+ * @brief Enables the USB1_OTG_HS ULPI peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSB1_HSULPI(lp) rccEnableAHB1(RCC_AHB1ENR_USB1OTGHSULPIEN, lp)
+
+/**
+ * @brief Disables the USB1_OTG_HS peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSB1_HSULPI() rccDisableAHB1(RCC_AHB1ENR_USB1OTGHSULPIEN)
+
+#if !defined(STM32H723xx)
+
+/**
+ * @brief Enables the USB2_OTG_HS ULPI peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSB2_HSULPI(lp) rccEnableAHB1(RCC_AHB1ENR_USB2OTGHSULPIEN, lp)
+
+/**
+ * @brief Disables the USB2_OTG_HS peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSB2_HSULPI() rccDisableAHB1(RCC_AHB1ENR_USB2OTGHSULPIEN)
+
+#endif // !defined(STM32H723xx)
+/** @} */
+
+/**
+ * @name QUADSPI peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the QUADSPI1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableQUADSPI1(lp) rccEnableAHB3(RCC_AHB3ENR_QSPIEN, lp)
+
+/**
+ * @brief Disables the QUADSPI1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableQUADSPI1() rccDisableAHB3(RCC_AHB3ENR_QSPIEN)
+
+/**
+ * @brief Resets the QUADSPI1 peripheral.
+ *
+ * @api
+ */
+#define rccResetQUADSPI1() rccResetAHB3(RCC_AHB3RSTR_QSPIRST)
+/** @} */
+
+/**
+ * @name RNG peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the RNG peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableRNG(lp) rccEnableAHB2(RCC_AHB2ENR_RNGEN, lp)
+
+/**
+ * @brief Disables the RNG peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableRNG() rccDisableAHB2(RCC_AHB2ENR_RNGEN)
+
+/**
+ * @brief Resets the RNG peripheral.
+ *
+ * @api
+ */
+#define rccResetRNG() rccResetAHB2(RCC_AHB2RSTR_RNGRST)
+/** @} */
+
+/**
+ * @name SDMMC peripheral specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the SDMMC1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSDMMC1(lp) rccEnableAHB3(RCC_AHB3ENR_SDMMC1EN, lp)
+
+/**
+ * @brief Disables the SDMMC1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSDMMC1() rccDisableAHB3(RCC_AHB3ENR_SDMMC1EN)
+
+/**
+ * @brief Resets the SDMMC1 peripheral.
+ *
+ * @api
+ */
+#define rccResetSDMMC1() rccResetAHB3(RCC_AHB3RSTR_SDMMC1RST)
+
+/**
+ * @brief Enables the SDMMC2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSDMMC2(lp) rccEnableAHB3(RCC_AHB3ENR_SDMMC2EN, lp)
+
+/**
+ * @brief Disables the SDMMC2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSDMMC2() rccDisableAHB3(RCC_AHB3ENR_SDMMC2EN)
+
+/**
+ * @brief Resets the SDMMC2 peripheral.
+ *
+ * @api
+ */
+#define rccResetSDMMC2() rccResetAHB3(RCC_AHB3RSTR_SDMMC2RST)
+/** @} */
+
+/**
+ * @name SPI peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the SPI1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSPI1(lp) rccEnableAPB2(RCC_APB2ENR_SPI1EN, lp)
+
+/**
+ * @brief Disables the SPI1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSPI1() rccDisableAPB2(RCC_APB2ENR_SPI1EN)
+
+/**
+ * @brief Resets the SPI1 peripheral.
+ *
+ * @api
+ */
+#define rccResetSPI1() rccResetAPB2(RCC_APB2RSTR_SPI1RST)
+
+/**
+ * @brief Enables the SPI2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSPI2(lp) rccEnableAPB1L(RCC_APB1LENR_SPI2EN, lp)
+
+/**
+ * @brief Disables the SPI2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSPI2() rccDisableAPB1L(RCC_APB1LENR_SPI2EN)
+
+/**
+ * @brief Resets the SPI2 peripheral.
+ *
+ * @api
+ */
+#define rccResetSPI2() rccResetAPB1L(RCC_APB1LRSTR_SPI2RST)
+
+/**
+ * @brief Enables the SPI3 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSPI3(lp) rccEnableAPB1L(RCC_APB1LENR_SPI3EN, lp)
+
+/**
+ * @brief Disables the SPI3 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSPI3() rccDisableAPB1L(RCC_APB1LENR_SPI3EN)
+
+/**
+ * @brief Resets the SPI3 peripheral.
+ *
+ * @api
+ */
+#define rccResetSPI3() rccResetAPB1L(RCC_APB1LRSTR_SPI3RST)
+
+/**
+ * @brief Enables the SPI4 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSPI4(lp) rccEnableAPB2(RCC_APB2ENR_SPI4EN, lp)
+
+/**
+ * @brief Disables the SPI4 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSPI4() rccDisableAPB2(RCC_APB2ENR_SPI4EN)
+
+/**
+ * @brief Resets the SPI4 peripheral.
+ *
+ * @api
+ */
+#define rccResetSPI4() rccResetAPB2(RCC_APB2RSTR_SPI4RST)
+
+/**
+ * @brief Enables the SPI5 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSPI5(lp) rccEnableAPB2(RCC_APB2ENR_SPI5EN, lp)
+
+/**
+ * @brief Disables the SPI5 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSPI5() rccDisableAPB2(RCC_APB2ENR_SPI5EN)
+
+/**
+ * @brief Resets the SPI5 peripheral.
+ *
+ * @api
+ */
+#define rccResetSPI5() rccResetAPB2(RCC_APB2RSTR_SPI5RST)
+
+/**
+ * @brief Enables the SPI6 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableSPI6(lp) rccEnableAPB4(RCC_APB4ENR_SPI6EN, lp)
+
+/**
+ * @brief Disables the SPI6 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableSPI6() rccDisableAPB4(RCC_APB4ENR_SPI6EN)
+
+/**
+ * @brief Resets the SPI6 peripheral.
+ *
+ * @api
+ */
+#define rccResetSPI6() rccResetAPB4(RCC_APB4RSTR_SPI6RST)
+/** @} */
+
+/**
+ * @name TIM peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the TIM1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM1(lp) rccEnableAPB2(RCC_APB2ENR_TIM1EN, lp)
+
+/**
+ * @brief Disables the TIM1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM1() rccDisableAPB2(RCC_APB2ENR_TIM1EN)
+
+/**
+ * @brief Resets the TIM1 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM1() rccResetAPB2(RCC_APB2RSTR_TIM1RST)
+
+/**
+ * @brief Enables the TIM2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM2(lp) rccEnableAPB1L(RCC_APB1LENR_TIM2EN, lp)
+
+/**
+ * @brief Disables the TIM2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM2() rccDisableAPB1L(RCC_APB1LENR_TIM2EN)
+
+/**
+ * @brief Resets the TIM2 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM2() rccResetAPB1L(RCC_APB1LRSTR_TIM2RST)
+
+/**
+ * @brief Enables the TIM3 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM3(lp) rccEnableAPB1L(RCC_APB1LENR_TIM3EN, lp)
+
+/**
+ * @brief Disables the TIM3 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM3() rccDisableAPB1L(RCC_APB1LENR_TIM3EN)
+
+/**
+ * @brief Resets the TIM3 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM3() rccResetAPB1L(RCC_APB1LRSTR_TIM3RST)
+
+/**
+ * @brief Enables the TIM4 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM4(lp) rccEnableAPB1L(RCC_APB1LENR_TIM4EN, lp)
+
+/**
+ * @brief Disables the TIM4 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM4() rccDisableAPB1L(RCC_APB1LENR_TIM4EN)
+
+/**
+ * @brief Resets the TIM4 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM4() rccResetAPB1L(RCC_APB1LRSTR_TIM4RST)
+
+/**
+ * @brief Enables the TIM5 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM5(lp) rccEnableAPB1L(RCC_APB1LENR_TIM5EN, lp)
+
+/**
+ * @brief Disables the TIM5 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM5() rccDisableAPB1L(RCC_APB1LENR_TIM5EN)
+
+/**
+ * @brief Resets the TIM5 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM5() rccResetAPB1L(RCC_APB1LRSTR_TIM5RST)
+
+/**
+ * @brief Enables the TIM6 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM6(lp) rccEnableAPB1L(RCC_APB1LENR_TIM6EN, lp)
+
+/**
+ * @brief Disables the TIM6 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM6() rccDisableAPB1L(RCC_APB1LENR_TIM6EN)
+
+/**
+ * @brief Resets the TIM6 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM6() rccResetAPB1L(RCC_APB1LRSTR_TIM6RST)
+
+/**
+ * @brief Enables the TIM7 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM7(lp) rccEnableAPB1L(RCC_APB1LENR_TIM7EN, lp)
+
+/**
+ * @brief Disables the TIM7 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM7() rccDisableAPB1L(RCC_APB1LENR_TIM7EN)
+
+/**
+ * @brief Resets the TIM7 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM7() rccResetAPB1L(RCC_APB1LRSTR_TIM7RST)
+
+/**
+ * @brief Enables the TIM8 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM8(lp) rccEnableAPB2(RCC_APB2ENR_TIM8EN, lp)
+
+/**
+ * @brief Disables the TIM8 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM8() rccDisableAPB2(RCC_APB2ENR_TIM8EN)
+
+/**
+ * @brief Resets the TIM8 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM8() rccResetAPB2(RCC_APB2RSTR_TIM8RST)
+
+/**
+ * @brief Enables the TIM12 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM12(lp) rccEnableAPB1L(RCC_APB1LENR_TIM12EN, lp)
+
+/**
+ * @brief Disables the TIM12 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM12() rccDisableAPB1L(RCC_APB1LENR_TIM12EN)
+
+/**
+ * @brief Resets the TIM12 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM12() rccResetAPB1L(RCC_APB1LRSTR_TIM12RST)
+
+/**
+ * @brief Enables the TIM13 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM13(lp) rccEnableAPB1L(RCC_APB1LENR_TIM13EN, lp)
+
+/**
+ * @brief Disables the TIM13 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM13() rccDisableAPB1L(RCC_APB1LENR_TIM13EN)
+
+/**
+ * @brief Resets the TIM13 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM13() rccResetAPB1L(RCC_APB1LRSTR_TIM13RST)
+
+/**
+ * @brief Enables the TIM14 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM14(lp) rccEnableAPB1L(RCC_APB1LENR_TIM14EN, lp)
+
+/**
+ * @brief Disables the TIM14 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM14() rccDisableAPB1L(RCC_APB1LENR_TIM14EN)
+
+/**
+ * @brief Resets the TIM14 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM14() rccResetAPB1L(RCC_APB1LRSTR_TIM14RST)
+
+/**
+ * @brief Enables the TIM15 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM15(lp) rccEnableAPB2(RCC_APB2ENR_TIM15EN, lp)
+
+/**
+ * @brief Disables the TIM15 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM15() rccDisableAPB2(RCC_APB2ENR_TIM15EN)
+
+/**
+ * @brief Resets the TIM15 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM15() rccResetAPB2(RCC_APB2RSTR_TIM15RST)
+
+/**
+ * @brief Enables the TIM16 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM16(lp) rccEnableAPB2(RCC_APB2ENR_TIM16EN, lp)
+
+/**
+ * @brief Disables the TIM16 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM16() rccDisableAPB2(RCC_APB2ENR_TIM16EN)
+
+/**
+ * @brief Resets the TIM16 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM16() rccResetAPB2(RCC_APB2RSTR_TIM16RST)
+
+/**
+ * @brief Enables the TIM17 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableTIM17(lp) rccEnableAPB2(RCC_APB2ENR_TIM17EN, lp)
+
+/**
+ * @brief Disables the TIM17 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableTIM17() rccDisableAPB2(RCC_APB2ENR_TIM17EN)
+
+/**
+ * @brief Resets the TIM17 peripheral.
+ *
+ * @api
+ */
+#define rccResetTIM17() rccResetAPB2(RCC_APB2RSTR_TIM17RST)
+/** @} */
+
+/**
+ * @name USART/UART peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the USART1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSART1(lp) rccEnableAPB2(RCC_APB2ENR_USART1EN, lp)
+
+/**
+ * @brief Disables the USART1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSART1() rccDisableAPB2(RCC_APB2ENR_USART1EN)
+
+/**
+ * @brief Resets the USART1 peripheral.
+ *
+ * @api
+ */
+#define rccResetUSART1() rccResetAPB2(RCC_APB2RSTR_USART1RST)
+
+/**
+ * @brief Enables the USART2 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSART2(lp) rccEnableAPB1L(RCC_APB1LENR_USART2EN, lp)
+
+/**
+ * @brief Disables the USART2 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSART2() rccDisableAPB1L(RCC_APB1LENR_USART2EN)
+
+/**
+ * @brief Resets the USART2 peripheral.
+ *
+ * @api
+ */
+#define rccResetUSART2() rccResetAPB1L(RCC_APB1LRSTR_USART2RST)
+
+/**
+ * @brief Enables the USART3 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSART3(lp) rccEnableAPB1L(RCC_APB1LENR_USART3EN, lp)
+
+/**
+ * @brief Disables the USART3 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSART3() rccDisableAPB1L(RCC_APB1LENR_USART3EN)
+
+/**
+ * @brief Resets the USART3 peripheral.
+ *
+ * @api
+ */
+#define rccResetUSART3() rccResetAPB1L(RCC_APB1LRSTR_USART3RST)
+
+/**
+ * @brief Enables the UART4 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUART4(lp) rccEnableAPB1L(RCC_APB1LENR_UART4EN, lp)
+
+/**
+ * @brief Disables the UART4 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUART4() rccDisableAPB1L(RCC_APB1LENR_UART4EN)
+
+/**
+ * @brief Resets the UART4 peripheral.
+ *
+ * @api
+ */
+#define rccResetUART4() rccResetAPB1L(RCC_APB1LRSTR_UART4RST)
+
+/**
+ * @brief Enables the UART5 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUART5(lp) rccEnableAPB1L(RCC_APB1LENR_UART5EN, lp)
+
+/**
+ * @brief Disables the UART5 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUART5() rccDisableAPB1L(RCC_APB1LENR_UART5EN)
+
+/**
+ * @brief Resets the UART5 peripheral.
+ *
+ * @api
+ */
+#define rccResetUART5() rccResetAPB1L(RCC_APB1LRSTR_UART5RST)
+
+/**
+ * @brief Enables the USART6 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUSART6(lp) rccEnableAPB2(RCC_APB2ENR_USART6EN, lp)
+
+/**
+ * @brief Disables the USART6 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUSART6() rccDisableAPB2(RCC_APB2ENR_USART6EN)
+
+/**
+ * @brief Resets the USART6 peripheral.
+ *
+ * @api
+ */
+#define rccResetUSART6() rccResetAPB2(RCC_APB2RSTR_USART6RST)
+
+/**
+ * @brief Enables the UART7 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUART7(lp) rccEnableAPB1L(RCC_APB1LENR_UART7EN, lp)
+
+/**
+ * @brief Disables the UART7 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUART7() rccDisableAPB1L(RCC_APB1LENR_UART7EN)
+
+/**
+ * @brief Resets the UART7 peripheral.
+ *
+ * @api
+ */
+#define rccResetUART7() rccResetAPB1L(RCC_APB1LRSTR_UART7RST)
+
+/**
+ * @brief Enables the UART8 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableUART8(lp) rccEnableAPB1L(RCC_APB1LENR_UART8EN, lp)
+
+/**
+ * @brief Disables the UART8 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableUART8() rccDisableAPB1L(RCC_APB1LENR_UART8EN)
+
+/**
+ * @brief Resets the UART8 peripheral.
+ *
+ * @api
+ */
+#define rccResetUART8() rccResetAPB1L(RCC_APB1LRSTR_UART8RST)
+/** @} */
+
+/**
+ * @brief Enables the LPUART1 peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableLPUART1(lp) rccEnableAPB4(RCC_APB4ENR_LPUART1EN, lp)
+
+/**
+ * @brief Disables the LPUART1 peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableLPUART1() rccDisableAPB4(RCC_APB4ENR_LPUART1EN)
+
+/**
+ * @brief Resets the LPUART1 peripheral.
+ *
+ * @api
+ */
+#define rccResetLPUART1() rccResetAPB4(RCC_APB4RSTR_LPUART1RST)
+/** @} */
+
+/**
+ * @name LTDC peripheral specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the LTDC peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableLTDC(lp) rccEnableAPB3(RCC_APB3ENR_LTDCEN, lp)
+
+/**
+ * @brief Disables the LTDC peripheral clock.
+. *
+ * @api
+ */
+#define rccDisableLTDC() rccDisableAPB3(RCC_APB3ENR_LTDCEN)
+
+/**
+ * @brief Resets the LTDC peripheral.
+ *
+ * @api
+ */
+#define rccResetLTDC() rccResetAPB3(RCC_APB3RSTR_LTDCRST)
+
+/**
+ * @name DMA2D peripheral specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the DMA2D peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableDMA2D(lp) rccEnableAHB3(RCC_AHB3ENR_DMA2DEN, lp)
+
+/**
+ * @brief Disables the DMA2D peripheral clock.
+ *
+ * @api
+ */
+#define rccDisableDMA2D() rccDisableAHB3(RCC_AHB3ENR_DMA2DEN)
+
+/**
+ * @brief Resets the DMA2D peripheral.
+ *
+ * @api
+ */
+#define rccResetDMA2D() rccResetAHB3(RCC_AHB3RSTR_DMA2DRST)
+/** @} */
+
+/**
+ * @name FSMC peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the FSMC peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#if defined(STM32_FSMC_IS_FMC)
+ #define rccEnableFSMC(lp) rccEnableAHB3(RCC_AHB3ENR_FMCEN, lp)
+#else
+ #define rccEnableFSMC(lp) rccEnableAHB3(RCC_AHB3ENR_FSMCEN, lp)
+#endif
+
+/**
+ * @brief Disables the FSMC peripheral clock.
+ *
+ * @api
+ */
+#if defined(STM32_FSMC_IS_FMC)
+ #define rccDisableFSMC() rccDisableAHB3(RCC_AHB3ENR_FMCEN)
+#else
+ #define rccDisableFSMC() rccDisableAHB3(RCC_AHB3ENR_FSMCEN)
+#endif
+
+/**
+ * @brief Resets the FSMC peripheral.
+ *
+ * @api
+ */
+#if defined(STM32_FSMC_IS_FMC)
+ #define rccResetFSMC() rccResetAHB3(RCC_AHB3RSTR_FMCRST)
+#else
+ #define rccResetFSMC() rccResetAHB3(RCC_AHB3RSTR_FSMCRST)
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32_RCC_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h new file mode 100644 index 0000000..51e88e5 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/STM32H7xx/stm32_registry.h @@ -0,0 +1,778 @@ +/*
+ 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 STM32H7xx/stm32_registry.h
+ * @brief STM32H7xx capabilities registry.
+ *
+ * @addtogroup HAL
+ * @{
+ */
+
+#ifndef STM32_REGISTRY_H
+#define STM32_REGISTRY_H
+
+/*===========================================================================*/
+/* Platform capabilities. */
+/*===========================================================================*/
+
+/* Cores.*/
+#if defined(STM32H750xx) || defined(STM32H742xx) || \
+ defined(STM32H743xx) || defined(STM32H753xx) || \
+ defined(STM32H723xx)
+#define STM32_HAS_M7 TRUE
+#define STM32_HAS_M4 FALSE
+#else
+#define STM32_HAS_M7 TRUE
+#define STM32_HAS_M4 TRUE
+#endif
+
+/**
+ * @name STM32H7xx capabilities
+ * @{
+ */
+
+/*===========================================================================*/
+/* Common. */
+/*===========================================================================*/
+
+/* RNG attributes.*/
+#define STM32_HAS_RNG1 TRUE
+
+/* I2C attributes.*/
+#define STM32_I2C4_USE_BDMA TRUE
+
+/*===========================================================================*/
+/* STM32H743xx, STM32H753xx, STM32H745xx, STM32H755xx, STM32H747xx, */
+/* STM32H757xx. */
+/*===========================================================================*/
+#if defined(STM32H743xx) || defined(STM32H753xx) || \
+ defined(STM32H745xx) || defined(STM32H755xx) || \
+ defined(STM32H747xx) || defined(STM32H757xx) || \
+ defined(__DOXYGEN__)
+
+/* ADC attributes.*/
+#define STM32_HAS_ADC1 TRUE
+#define STM32_HAS_ADC2 TRUE
+#define STM32_HAS_ADC3 TRUE
+#define STM32_HAS_ADC4 FALSE
+
+#define STM32_HAS_SDADC1 FALSE
+#define STM32_HAS_SDADC2 FALSE
+#define STM32_HAS_SDADC3 FALSE
+
+/* CAN attributes.*/
+#define STM32_HAS_FDCAN1 TRUE
+#define STM32_HAS_FDCAN2 TRUE
+#define STM32_HAS_FDCAN3 FALSE
+#define STM32_FDCAN_FLS_NBR 128U
+#define STM32_FDCAN_FLE_NBR 128U
+#define STM32_FDCAN_RF0_NBR 64U
+#define STM32_FDCAN_RF1_NBR 64U
+#define STM32_FDCAN_RB_NBR 64U
+#define STM32_FDCAN_TEF_NBR 32U
+#define STM32_FDCAN_TB_NBR 32U
+#define STM32_FDCAN_TM_NBR 64U
+
+/* DAC attributes.*/
+#define STM32_HAS_DAC1_CH1 TRUE
+#define STM32_HAS_DAC1_CH2 TRUE
+#define STM32_HAS_DAC2_CH1 FALSE
+#define STM32_HAS_DAC2_CH2 FALSE
+
+/* BDMA attributes.*/
+#define STM32_HAS_BDMA1 TRUE
+
+/* DMA attributes.*/
+#define STM32_ADVANCED_DMA TRUE
+#define STM32_DMA_SUPPORTS_DMAMUX TRUE
+
+#define STM32_HAS_DMA1 TRUE
+#define STM32_HAS_DMA2 TRUE
+
+/* MDMA attributes.*/
+#define STM32_HAS_MDMA1 TRUE
+
+/* ETH attributes.*/
+#define STM32_HAS_ETH TRUE
+
+/* EXTI attributes.*/
+#define STM32_EXTI_ENHANCED
+#define STM32_EXTI_NUM_LINES 34
+#define STM32_EXTI_IMR1_MASK 0x1F800000U
+#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU
+
+/* GPIO attributes.*/
+#define STM32_HAS_GPIOA TRUE
+#define STM32_HAS_GPIOB TRUE
+#define STM32_HAS_GPIOC TRUE
+#define STM32_HAS_GPIOD TRUE
+#define STM32_HAS_GPIOE TRUE
+#define STM32_HAS_GPIOH TRUE
+#define STM32_HAS_GPIOF TRUE
+#define STM32_HAS_GPIOG TRUE
+#define STM32_HAS_GPIOI TRUE
+#define STM32_HAS_GPIOJ TRUE
+#define STM32_HAS_GPIOK TRUE
+#define STM32_GPIO_EN_MASK (RCC_AHB4ENR_GPIOAEN | \
+ RCC_AHB4ENR_GPIOBEN | \
+ RCC_AHB4ENR_GPIOCEN | \
+ RCC_AHB4ENR_GPIODEN | \
+ RCC_AHB4ENR_GPIOEEN | \
+ RCC_AHB4ENR_GPIOFEN | \
+ RCC_AHB4ENR_GPIOGEN | \
+ RCC_AHB4ENR_GPIOHEN | \
+ RCC_AHB4ENR_GPIOIEN | \
+ RCC_AHB4ENR_GPIOJEN | \
+ RCC_AHB4ENR_GPIOKEN)
+
+/* I2C attributes.*/
+#define STM32_HAS_I2C1 TRUE
+#define STM32_HAS_I2C2 TRUE
+#define STM32_HAS_I2C3 TRUE
+#define STM32_HAS_I2C4 TRUE
+
+/* QUADSPI attributes.*/
+#define STM32_HAS_QUADSPI1 TRUE
+#define STM32_HAS_QUADSPI2 FALSE
+
+/* RTC attributes.*/
+#define STM32_HAS_RTC TRUE
+#define STM32_RTC_HAS_SUBSECONDS TRUE
+#define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE
+#define STM32_RTC_NUM_ALARMS 2
+#define STM32_RTC_HAS_INTERRUPTS FALSE
+
+/* SDMMC attributes.*/
+#define STM32_HAS_SDMMC1 TRUE
+#define STM32_HAS_SDMMC2 TRUE
+
+/* SPI attributes.*/
+#define STM32_HAS_SPI1 TRUE
+#define STM32_SPI1_SUPPORTS_I2S TRUE
+#define STM32_SPI1_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI2 TRUE
+#define STM32_SPI2_SUPPORTS_I2S TRUE
+#define STM32_SPI2_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI3 TRUE
+#define STM32_SPI3_SUPPORTS_I2S TRUE
+#define STM32_SPI3_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI4 TRUE
+#define STM32_SPI4_SUPPORTS_I2S FALSE
+
+#define STM32_HAS_SPI5 TRUE
+#define STM32_SPI5_SUPPORTS_I2S FALSE
+
+#define STM32_HAS_SPI6 TRUE
+#define STM32_SPI6_SUPPORTS_I2S FALSE
+
+/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 6
+
+#define STM32_HAS_TIM1 TRUE
+#define STM32_TIM1_IS_32BITS FALSE
+#define STM32_TIM1_CHANNELS 6
+
+#define STM32_HAS_TIM2 TRUE
+#define STM32_TIM2_IS_32BITS TRUE
+#define STM32_TIM2_CHANNELS 4
+
+#define STM32_HAS_TIM3 TRUE
+#define STM32_TIM3_IS_32BITS FALSE
+#define STM32_TIM3_CHANNELS 4
+
+#define STM32_HAS_TIM4 TRUE
+#define STM32_TIM4_IS_32BITS FALSE
+#define STM32_TIM4_CHANNELS 4
+
+#define STM32_HAS_TIM5 TRUE
+#define STM32_TIM5_IS_32BITS TRUE
+#define STM32_TIM5_CHANNELS 4
+
+#define STM32_HAS_TIM6 TRUE
+#define STM32_TIM6_IS_32BITS FALSE
+#define STM32_TIM6_CHANNELS 0
+
+#define STM32_HAS_TIM7 TRUE
+#define STM32_TIM7_IS_32BITS FALSE
+#define STM32_TIM7_CHANNELS 0
+
+#define STM32_HAS_TIM8 TRUE
+#define STM32_TIM8_IS_32BITS FALSE
+#define STM32_TIM8_CHANNELS 6
+
+#define STM32_HAS_TIM12 TRUE
+#define STM32_TIM12_IS_32BITS FALSE
+#define STM32_TIM12_CHANNELS 2
+
+#define STM32_HAS_TIM13 TRUE
+#define STM32_TIM13_IS_32BITS FALSE
+#define STM32_TIM13_CHANNELS 1
+
+#define STM32_HAS_TIM14 TRUE
+#define STM32_TIM14_IS_32BITS FALSE
+#define STM32_TIM14_CHANNELS 1
+
+#define STM32_HAS_TIM15 FALSE
+#define STM32_TIM15_IS_32BITS FALSE
+#define STM32_TIM15_CHANNELS 2
+
+#define STM32_HAS_TIM16 FALSE
+#define STM32_TIM16_IS_32BITS FALSE
+#define STM32_TIM16_CHANNELS 1
+
+#define STM32_HAS_TIM17 FALSE
+#define STM32_TIM17_IS_32BITS FALSE
+#define STM32_TIM17_CHANNELS 1
+
+#define STM32_HAS_TIM9 FALSE
+#define STM32_HAS_TIM10 FALSE
+#define STM32_HAS_TIM11 FALSE
+#define STM32_HAS_TIM18 FALSE
+#define STM32_HAS_TIM19 FALSE
+#define STM32_HAS_TIM20 FALSE
+#define STM32_HAS_TIM21 FALSE
+#define STM32_HAS_TIM22 FALSE
+
+/* USART attributes.*/
+#define STM32_HAS_USART1 TRUE
+#define STM32_HAS_USART2 TRUE
+#define STM32_HAS_USART3 TRUE
+#define STM32_HAS_UART4 TRUE
+#define STM32_HAS_UART5 TRUE
+#define STM32_HAS_USART6 TRUE
+#define STM32_HAS_UART7 TRUE
+#define STM32_HAS_UART8 TRUE
+#define STM32_HAS_LPUART1 TRUE
+
+/* USB attributes.*/
+#define STM32_OTG_STEPPING 2
+#define STM32_HAS_OTG1 TRUE
+#define STM32_OTG1_ENDPOINTS 8
+
+#define STM32_HAS_OTG2 TRUE
+#define STM32_OTG2_ENDPOINTS 8
+
+#define STM32_HAS_USB FALSE
+
+/* IWDG attributes.*/
+#define STM32_HAS_IWDG TRUE
+#define STM32_IWDG_IS_WINDOWED TRUE
+
+/* LTDC attributes.*/
+#define STM32_HAS_LTDC TRUE
+
+/* DMA2D attributes.*/
+#define STM32_HAS_DMA2D TRUE
+
+/* FSMC attributes.*/
+#define STM32_HAS_FSMC TRUE
+#define STM32_FSMC_IS_FMC TRUE
+
+/* CRC attributes.*/
+#define STM32_HAS_CRC TRUE
+#define STM32_CRC_PROGRAMMABLE TRUE
+
+/* DCMI attributes.*/
+#define STM32_HAS_DCMI TRUE
+
+#endif /* defined(STM32H743xx) || defined(STM32H753xx) */
+/** @} */
+
+/*===========================================================================*/
+/* STM32H750xx. */
+/*===========================================================================*/
+#if defined(STM32H750xx) || \
+ defined(__DOXYGEN__)
+
+/* ADC attributes.*/
+#define STM32_HAS_ADC1 TRUE
+#define STM32_HAS_ADC2 TRUE
+#define STM32_HAS_ADC3 FALSE
+#define STM32_HAS_ADC4 FALSE
+
+#define STM32_HAS_SDADC1 FALSE
+#define STM32_HAS_SDADC2 FALSE
+#define STM32_HAS_SDADC3 FALSE
+
+/* CAN attributes.*/
+#define STM32_HAS_FDCAN1 TRUE
+#define STM32_HAS_FDCAN2 TRUE
+
+/* DAC attributes.*/
+#define STM32_HAS_DAC1_CH1 TRUE
+#define STM32_HAS_DAC1_CH2 TRUE
+#define STM32_HAS_DAC2_CH1 FALSE
+#define STM32_HAS_DAC2_CH2 FALSE
+
+/* BDMA attributes.*/
+#define STM32_HAS_BDMA1 TRUE
+
+/* DMA attributes.*/
+#define STM32_ADVANCED_DMA TRUE
+#define STM32_DMA_SUPPORTS_DMAMUX TRUE
+
+#define STM32_HAS_DMA1 TRUE
+#define STM32_HAS_DMA2 TRUE
+
+/* MDMA attributes.*/
+#define STM32_HAS_MDMA1 TRUE
+
+/* ETH attributes.*/
+#define STM32_HAS_ETH TRUE
+
+/* EXTI attributes.*/
+#define STM32_EXTI_ENHANCED
+#define STM32_EXTI_NUM_LINES 34
+#define STM32_EXTI_IMR1_MASK 0x1F800000U
+#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU
+
+/* GPIO attributes.*/
+#define STM32_HAS_GPIOA TRUE
+#define STM32_HAS_GPIOB TRUE
+#define STM32_HAS_GPIOC TRUE
+#define STM32_HAS_GPIOD TRUE
+#define STM32_HAS_GPIOE TRUE
+#define STM32_HAS_GPIOH TRUE
+#define STM32_HAS_GPIOF TRUE
+#define STM32_HAS_GPIOG TRUE
+#define STM32_HAS_GPIOI TRUE
+#define STM32_HAS_GPIOJ TRUE
+#define STM32_HAS_GPIOK TRUE
+#define STM32_GPIO_EN_MASK (RCC_AHB4ENR_GPIOAEN | \
+ RCC_AHB4ENR_GPIOBEN | \
+ RCC_AHB4ENR_GPIOCEN | \
+ RCC_AHB4ENR_GPIODEN | \
+ RCC_AHB4ENR_GPIOEEN | \
+ RCC_AHB4ENR_GPIOFEN | \
+ RCC_AHB4ENR_GPIOGEN | \
+ RCC_AHB4ENR_GPIOHEN | \
+ RCC_AHB4ENR_GPIOIEN | \
+ RCC_AHB4ENR_GPIOJEN | \
+ RCC_AHB4ENR_GPIOKEN)
+
+/* I2C attributes.*/
+#define STM32_HAS_I2C1 TRUE
+#define STM32_HAS_I2C2 TRUE
+#define STM32_HAS_I2C3 TRUE
+#define STM32_HAS_I2C4 TRUE
+
+/* QUADSPI attributes.*/
+#define STM32_HAS_QUADSPI1 TRUE
+#define STM32_HAS_QUADSPI2 FALSE
+
+/* RTC attributes.*/
+#define STM32_HAS_RTC TRUE
+#define STM32_RTC_HAS_SUBSECONDS TRUE
+#define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE
+#define STM32_RTC_NUM_ALARMS 2
+#define STM32_RTC_HAS_INTERRUPTS FALSE
+
+/* SDMMC attributes.*/
+#define STM32_HAS_SDMMC1 TRUE
+#define STM32_HAS_SDMMC2 TRUE
+
+/* SPI attributes.*/
+#define STM32_HAS_SPI1 TRUE
+#define STM32_SPI1_SUPPORTS_I2S TRUE
+#define STM32_SPI1_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI2 TRUE
+#define STM32_SPI2_SUPPORTS_I2S TRUE
+#define STM32_SPI2_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI3 TRUE
+#define STM32_SPI3_SUPPORTS_I2S TRUE
+#define STM32_SPI3_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI4 TRUE
+#define STM32_SPI4_SUPPORTS_I2S FALSE
+
+#define STM32_HAS_SPI5 TRUE
+#define STM32_SPI5_SUPPORTS_I2S FALSE
+
+#define STM32_HAS_SPI6 TRUE
+#define STM32_SPI6_SUPPORTS_I2S FALSE
+
+/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 6
+
+#define STM32_HAS_TIM1 TRUE
+#define STM32_TIM1_IS_32BITS FALSE
+#define STM32_TIM1_CHANNELS 6
+
+#define STM32_HAS_TIM2 TRUE
+#define STM32_TIM2_IS_32BITS TRUE
+#define STM32_TIM2_CHANNELS 4
+
+#define STM32_HAS_TIM3 TRUE
+#define STM32_TIM3_IS_32BITS FALSE
+#define STM32_TIM3_CHANNELS 4
+
+#define STM32_HAS_TIM4 TRUE
+#define STM32_TIM4_IS_32BITS FALSE
+#define STM32_TIM4_CHANNELS 4
+
+#define STM32_HAS_TIM5 TRUE
+#define STM32_TIM5_IS_32BITS TRUE
+#define STM32_TIM5_CHANNELS 4
+
+#define STM32_HAS_TIM6 TRUE
+#define STM32_TIM6_IS_32BITS FALSE
+#define STM32_TIM6_CHANNELS 0
+
+#define STM32_HAS_TIM7 TRUE
+#define STM32_TIM7_IS_32BITS FALSE
+#define STM32_TIM7_CHANNELS 0
+
+#define STM32_HAS_TIM8 TRUE
+#define STM32_TIM8_IS_32BITS FALSE
+#define STM32_TIM8_CHANNELS 6
+
+#define STM32_HAS_TIM12 TRUE
+#define STM32_TIM12_IS_32BITS FALSE
+#define STM32_TIM12_CHANNELS 2
+
+#define STM32_HAS_TIM13 TRUE
+#define STM32_TIM13_IS_32BITS FALSE
+#define STM32_TIM13_CHANNELS 1
+
+#define STM32_HAS_TIM14 TRUE
+#define STM32_TIM14_IS_32BITS FALSE
+#define STM32_TIM14_CHANNELS 1
+
+#define STM32_HAS_TIM15 FALSE
+#define STM32_TIM15_IS_32BITS FALSE
+#define STM32_TIM15_CHANNELS 2
+
+#define STM32_HAS_TIM16 FALSE
+#define STM32_TIM16_IS_32BITS FALSE
+#define STM32_TIM16_CHANNELS 1
+
+#define STM32_HAS_TIM17 FALSE
+#define STM32_TIM17_IS_32BITS FALSE
+#define STM32_TIM17_CHANNELS 1
+
+#define STM32_HAS_TIM9 FALSE
+#define STM32_HAS_TIM10 FALSE
+#define STM32_HAS_TIM11 FALSE
+#define STM32_HAS_TIM18 FALSE
+#define STM32_HAS_TIM19 FALSE
+#define STM32_HAS_TIM20 FALSE
+#define STM32_HAS_TIM21 FALSE
+#define STM32_HAS_TIM22 FALSE
+
+/* USART attributes.*/
+#define STM32_HAS_USART1 TRUE
+#define STM32_HAS_USART2 TRUE
+#define STM32_HAS_USART3 TRUE
+#define STM32_HAS_UART4 TRUE
+#define STM32_HAS_UART5 TRUE
+#define STM32_HAS_USART6 TRUE
+#define STM32_HAS_UART7 TRUE
+#define STM32_HAS_UART8 TRUE
+#define STM32_HAS_LPUART1 TRUE
+
+/* USB attributes.*/
+#define STM32_OTG_STEPPING 2
+#define STM32_HAS_OTG1 TRUE
+#define STM32_OTG1_ENDPOINTS 8
+
+#define STM32_HAS_OTG2 TRUE
+#define STM32_OTG2_ENDPOINTS 8
+
+#define STM32_HAS_USB FALSE
+
+/* IWDG attributes.*/
+#define STM32_HAS_IWDG TRUE
+#define STM32_IWDG_IS_WINDOWED TRUE
+
+/* LTDC attributes.*/
+#define STM32_HAS_LTDC TRUE
+
+/* DMA2D attributes.*/
+#define STM32_HAS_DMA2D TRUE
+
+/* FSMC attributes.*/
+#define STM32_HAS_FSMC TRUE
+#define STM32_FSMC_IS_FMC TRUE
+
+/* CRC attributes.*/
+#define STM32_HAS_CRC TRUE
+#define STM32_CRC_PROGRAMMABLE TRUE
+
+/* DCMI attributes.*/
+#define STM32_HAS_DCMI TRUE
+
+#endif /* defined(STM32H750xx) */
+
+/*===========================================================================*/
+/* STM32H723xx. */
+/*===========================================================================*/
+#if defined(STM32H723xx) || defined(__DOXYGEN__)
+
+/* ADC attributes.*/
+#define STM32_HAS_ADC1 TRUE
+#define STM32_HAS_ADC2 TRUE
+#define STM32_HAS_ADC3 TRUE
+#define STM32_HAS_ADC4 FALSE
+
+#define STM32_HAS_SDADC1 FALSE
+#define STM32_HAS_SDADC2 FALSE
+#define STM32_HAS_SDADC3 FALSE
+
+/* CAN attributes.*/
+#define STM32_HAS_FDCAN1 TRUE
+#define STM32_HAS_FDCAN2 TRUE
+#define STM32_HAS_FDCAN3 FALSE
+#define STM32_FDCAN_FLS_NBR 128U
+#define STM32_FDCAN_FLE_NBR 128U
+#define STM32_FDCAN_RF0_NBR 64U
+#define STM32_FDCAN_RF1_NBR 64U
+#define STM32_FDCAN_RB_NBR 64U
+#define STM32_FDCAN_TEF_NBR 32U
+#define STM32_FDCAN_TB_NBR 32U
+#define STM32_FDCAN_TM_NBR 64U
+
+/* DAC attributes.*/
+#define STM32_HAS_DAC1_CH1 TRUE
+#define STM32_HAS_DAC1_CH2 TRUE
+#define STM32_HAS_DAC2_CH1 FALSE
+#define STM32_HAS_DAC2_CH2 FALSE
+
+/* BDMA attributes.*/
+#define STM32_HAS_BDMA1 TRUE
+
+/* DMA attributes.*/
+#define STM32_ADVANCED_DMA TRUE
+#define STM32_DMA_SUPPORTS_DMAMUX TRUE
+
+#define STM32_HAS_DMA1 TRUE
+#define STM32_HAS_DMA2 TRUE
+
+/* MDMA attributes.*/
+#define STM32_HAS_MDMA1 TRUE
+
+/* ETH attributes.*/
+#define STM32_HAS_ETH TRUE
+
+/* EXTI attributes.*/
+#define STM32_EXTI_ENHANCED
+#define STM32_EXTI_NUM_LINES 34
+#define STM32_EXTI_IMR1_MASK 0x1F800000U
+#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU
+
+/* GPIO attributes.*/
+#define STM32_HAS_GPIOA TRUE
+#define STM32_HAS_GPIOB TRUE
+#define STM32_HAS_GPIOC TRUE
+#define STM32_HAS_GPIOD TRUE
+#define STM32_HAS_GPIOE TRUE
+#define STM32_HAS_GPIOH TRUE
+#define STM32_HAS_GPIOF TRUE
+#define STM32_HAS_GPIOG TRUE
+#define STM32_HAS_GPIOI FALSE
+#define STM32_HAS_GPIOJ TRUE
+#define STM32_HAS_GPIOK TRUE
+#define STM32_GPIO_EN_MASK (RCC_AHB4ENR_GPIOAEN | \
+ RCC_AHB4ENR_GPIOBEN | \
+ RCC_AHB4ENR_GPIOCEN | \
+ RCC_AHB4ENR_GPIODEN | \
+ RCC_AHB4ENR_GPIOEEN | \
+ RCC_AHB4ENR_GPIOFEN | \
+ RCC_AHB4ENR_GPIOGEN | \
+ RCC_AHB4ENR_GPIOHEN | \
+ RCC_AHB4ENR_GPIOJEN | \
+ RCC_AHB4ENR_GPIOKEN)
+
+/* I2C attributes.*/
+#define STM32_HAS_I2C1 TRUE
+#define STM32_HAS_I2C2 TRUE
+#define STM32_HAS_I2C3 TRUE
+#define STM32_HAS_I2C4 TRUE
+#define STM32_HAS_I2C5 TRUE
+
+/* QUADSPI attributes.*/
+#define STM32_HAS_QUADSPI1 FALSE
+#define STM32_HAS_QUADSPI2 FALSE
+
+/* OCTOSPI attributes.*/
+#define STM32_HAS_OCTOSPI1 TRUE
+#define STM32_HAS_OCTOSPI2 TRUE
+
+/* RTC attributes.*/
+#define STM32_HAS_RTC TRUE
+#define STM32_RTC_HAS_SUBSECONDS TRUE
+#define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE
+#define STM32_RTC_NUM_ALARMS 2
+#define STM32_RTC_HAS_INTERRUPTS FALSE
+
+/* SDMMC attributes.*/
+#define STM32_HAS_SDMMC1 TRUE
+#define STM32_HAS_SDMMC2 TRUE
+
+/* SPI attributes.*/
+#define STM32_HAS_SPI1 TRUE
+#define STM32_SPI1_SUPPORTS_I2S TRUE
+#define STM32_SPI1_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI2 TRUE
+#define STM32_SPI2_SUPPORTS_I2S TRUE
+#define STM32_SPI2_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI3 TRUE
+#define STM32_SPI3_SUPPORTS_I2S TRUE
+#define STM32_SPI3_I2S_FULLDUPLEX TRUE
+
+#define STM32_HAS_SPI4 TRUE
+#define STM32_SPI4_SUPPORTS_I2S FALSE
+
+#define STM32_HAS_SPI5 TRUE
+#define STM32_SPI5_SUPPORTS_I2S FALSE
+
+#define STM32_HAS_SPI6 TRUE
+#define STM32_SPI6_SUPPORTS_I2S TRUE
+#define STM32_SPI6_I2S_FULLDUPLEX TRUE
+
+/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 6
+
+#define STM32_HAS_TIM1 TRUE
+#define STM32_TIM1_IS_32BITS FALSE
+#define STM32_TIM1_CHANNELS 6
+
+#define STM32_HAS_TIM2 TRUE
+#define STM32_TIM2_IS_32BITS TRUE
+#define STM32_TIM2_CHANNELS 4
+
+#define STM32_HAS_TIM3 TRUE
+#define STM32_TIM3_IS_32BITS FALSE
+#define STM32_TIM3_CHANNELS 4
+
+#define STM32_HAS_TIM4 TRUE
+#define STM32_TIM4_IS_32BITS FALSE
+#define STM32_TIM4_CHANNELS 4
+
+#define STM32_HAS_TIM5 TRUE
+#define STM32_TIM5_IS_32BITS TRUE
+#define STM32_TIM5_CHANNELS 4
+
+#define STM32_HAS_TIM6 TRUE
+#define STM32_TIM6_IS_32BITS FALSE
+#define STM32_TIM6_CHANNELS 0
+
+#define STM32_HAS_TIM7 TRUE
+#define STM32_TIM7_IS_32BITS FALSE
+#define STM32_TIM7_CHANNELS 0
+
+#define STM32_HAS_TIM8 TRUE
+#define STM32_TIM8_IS_32BITS FALSE
+#define STM32_TIM8_CHANNELS 6
+
+#define STM32_HAS_TIM12 TRUE
+#define STM32_TIM12_IS_32BITS FALSE
+#define STM32_TIM12_CHANNELS 2
+
+#define STM32_HAS_TIM13 TRUE
+#define STM32_TIM13_IS_32BITS FALSE
+#define STM32_TIM13_CHANNELS 1
+
+#define STM32_HAS_TIM14 TRUE
+#define STM32_TIM14_IS_32BITS FALSE
+#define STM32_TIM14_CHANNELS 1
+
+#define STM32_HAS_TIM15 TRUE
+#define STM32_TIM15_IS_32BITS FALSE
+#define STM32_TIM15_CHANNELS 2
+
+#define STM32_HAS_TIM16 TRUE
+#define STM32_TIM16_IS_32BITS FALSE
+#define STM32_TIM16_CHANNELS 1
+
+#define STM32_HAS_TIM17 TRUE
+#define STM32_TIM17_IS_32BITS FALSE
+#define STM32_TIM17_CHANNELS 1
+
+#define STM32_HAS_TIM23 TRUE
+#define STM32_TIM23_IS_32BITS TRUE
+#define STM32_TIM23_CHANNELS 4
+
+#define STM32_HAS_TIM24 TRUE
+#define STM32_TIM24_IS_32BITS TRUE
+#define STM32_TIM24_CHANNELS 4
+
+#define STM32_HAS_TIM9 FALSE
+#define STM32_HAS_TIM10 FALSE
+#define STM32_HAS_TIM11 FALSE
+#define STM32_HAS_TIM18 FALSE
+#define STM32_HAS_TIM19 FALSE
+#define STM32_HAS_TIM20 FALSE
+#define STM32_HAS_TIM21 FALSE
+#define STM32_HAS_TIM22 FALSE
+
+/* USART attributes.*/
+#define STM32_HAS_USART1 TRUE
+#define STM32_HAS_USART2 TRUE
+#define STM32_HAS_USART3 TRUE
+#define STM32_HAS_UART4 TRUE
+#define STM32_HAS_UART5 TRUE
+#define STM32_HAS_USART6 TRUE
+#define STM32_HAS_UART7 TRUE
+#define STM32_HAS_UART8 TRUE
+#define STM32_HAS_UART9 TRUE
+#define STM32_HAS_USART10 TRUE
+#define STM32_HAS_LPUART1 TRUE
+
+/* USB attributes.*/
+#define STM32_OTG_STEPPING 2
+#define STM32_HAS_OTG1 TRUE
+#define STM32_OTG1_ENDPOINTS 8
+
+#define STM32_HAS_OTG2 TRUE
+#define STM32_OTG2_ENDPOINTS 8
+
+#define STM32_HAS_USB FALSE
+
+/* IWDG attributes.*/
+#define STM32_HAS_IWDG TRUE
+#define STM32_IWDG_IS_WINDOWED TRUE
+
+/* LTDC attributes.*/
+#define STM32_HAS_LTDC TRUE
+
+/* DMA2D attributes.*/
+#define STM32_HAS_DMA2D TRUE
+
+/* FSMC attributes.*/
+#define STM32_HAS_FSMC TRUE
+#define STM32_FSMC_IS_FMC TRUE
+
+/* CRC attributes.*/
+#define STM32_HAS_CRC TRUE
+#define STM32_CRC_PROGRAMMABLE TRUE
+
+/* DCMI attributes.*/
+#define STM32_HAS_DCMI TRUE
+
+#endif /* defined(STM32H723xx) */
+/** @} */
+
+#endif /* STM32_REGISTRY_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt b/ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt new file mode 100644 index 0000000..c30cafc --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/STM32/todo.txt @@ -0,0 +1,4 @@ +- BOFF handling in DACv1.
+- Oversampling support for ADCv1 and ADCv3.
+- Implement missing ICU/PWM/GPT/ST units using shared IRQ handlers.
+- Implement I2S driver over SAI interfaces.
diff --git a/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/cache.h b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/cache.h new file mode 100644 index 0000000..52a92e7 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/cache.h @@ -0,0 +1,160 @@ +/*
+ 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 common/ARMCMx/cache.h
+ * @brief Cortex-Mx cache support macros and structures.
+ *
+ * @addtogroup COMMON_ARMCMx_CACHE
+ * @{
+ */
+
+#ifndef CACHE_H
+#define CACHE_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#if defined(__DCACHE_PRESENT) || defined(__DOXYGEN__)
+/**
+ * @brief Data cache line size, zero if there is no data cache.
+ */
+#define CACHE_LINE_SIZE 32U
+#else
+#define CACHE_LINE_SIZE 0U
+#endif
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+#if defined(__DCACHE_PRESENT) || defined(__DOXYGEN__)
+#if (__DCACHE_PRESENT != 0) || defined(__DOXYGEN__)
+/**
+ * @brief Aligns the specified size to a multiple of cache line size.
+ * @note This macros assumes that the size of the type @p t is a power of
+ * two and not greater than @p CACHE_LINE_SIZE.
+ *
+ * @param[in] t type of the buffer element
+ * @param[in] n number of buffer elements
+ */
+#define CACHE_SIZE_ALIGN(t, n) \
+ ((((((n) * sizeof (t)) - 1U) | (CACHE_LINE_SIZE - 1U)) + 1U) / sizeof (t))
+
+/**
+ * @brief Invalidates the data cache lines overlapping a memory buffer.
+ * @details This function is meant to make sure that data written in
+ * data cache is invalidated.
+ * @note On devices without data cache this function does nothing.
+ * @note The function does not consider the lower 5 bits of addresses,
+ * the buffers are meant to be aligned to a 32 bytes boundary or
+ * adjacent data can be invalidated as side effect.
+ *
+ * @param[in] saddr start address of the DMA buffer
+ * @param[in] n size of the DMA buffer in bytes
+ *
+ * @api
+ */
+#define cacheBufferInvalidate(saddr, n) { \
+ uint8_t *start = (uint8_t *)(saddr); \
+ uint8_t *end = start + (size_t)(n); \
+ __DSB(); \
+ while (start < end) { \
+ SCB->DCIMVAC = (uint32_t)start; \
+ start += CACHE_LINE_SIZE; \
+ } \
+ __DSB(); \
+ __ISB(); \
+}
+
+/**
+ * @brief Flushes the data cache lines overlapping a DMA buffer.
+ * @details This function is meant to make sure that data written in
+ * data cache is flushed to RAM.
+ * @note On devices without data cache this function does nothing.
+ * @note The function does not consider the lower 5 bits of addresses,
+ * the buffers are meant to be aligned to a 32 bytes boundary or
+ * adjacent data can be flushed as side effect.
+ *
+ * @param[in] saddr start address of the DMA buffer
+ * @param[in] n size of the DMA buffer in bytes
+ *
+ * @api
+ */
+#define cacheBufferFlush(saddr, n) { \
+ uint8_t *start = (uint8_t *)(saddr); \
+ uint8_t *end = start + (size_t)(n); \
+ __DSB(); \
+ while (start < end) { \
+ SCB->DCCIMVAC = (uint32_t)start; \
+ start += CACHE_LINE_SIZE; \
+ } \
+ __DSB(); \
+ __ISB(); \
+}
+
+#else /* __DCACHE_PRESENT == 0 */
+#define cacheBufferInvalidate(addr, size) { \
+ (void)(addr); \
+ (void)(size); \
+}
+#define cacheBufferFlush(addr, size) { \
+ (void)(addr); \
+ (void)(size); \
+}
+#endif
+
+#else /* !defined(__DCACHE_PRESENT) */
+#define CACHE_SIZE_ALIGN(t, n) (n)
+
+#define cacheBufferInvalidate(addr, size) { \
+ (void)(addr); \
+ (void)(size); \
+}
+#define cacheBufferFlush(addr, size) { \
+ (void)(addr); \
+ (void)(size); \
+}
+#endif
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CACHE_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/mpu_v7m.h b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/mpu_v7m.h new file mode 100644 index 0000000..11e691a --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/mpu_v7m.h @@ -0,0 +1,228 @@ +/*
+ 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 common/ARMCMx/mpu_v7m.h
+ * @brief ARMv7-M MPU support macros and structures.
+ *
+ * @addtogroup COMMON_ARMCMx_MPUv7M
+ * @{
+ */
+
+#ifndef MPUV7M_H
+#define MPUV7M_H
+
+/* Other layers may include another header named mpu.h which is perfectly
+ compatible, doing a check here to avoid name conflicts.*/
+#ifndef MPU_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name MPU registers definitions
+ * @{
+ */
+#define MPU_TYPE_SEPARATED (1U << 0U)
+#define MPU_TYPE_DREGION(n) (((n) >> 8U) & 255U)
+#define MPU_TYPE_IREGION(n) (((n) >> 16U) & 255U)
+
+#define MPU_CTRL_ENABLE (1U << 0U)
+#define MPU_CTRL_HFNMIENA (1U << 1U)
+#define MPU_CTRL_PRIVDEFENA (1U << 2U)
+
+#define MPU_RNR_REGION_MASK (255U << 0U)
+#define MPU_RNR_REGION(n) ((n) << 0U)
+
+#define MPU_RBAR_REGION_MASK (15U << 0U)
+#define MPU_RBAR_REGION(n) ((n) << 0U)
+#define MPU_RBAR_VALID (1U << 4U)
+#define MPU_RBAR_ADDR_MASK 0xFFFFFFE0U
+#define MPU_RBAR_ADDR(n) ((n) << 5U)
+
+#define MPU_RASR_ENABLE (1U << 0U)
+#define MPU_RASR_SIZE_MASK (31U << 1U)
+#define MPU_RASR_SIZE(n) ((n) << 1U)
+#define MPU_RASR_SIZE_32 MPU_RASR_SIZE(4U)
+#define MPU_RASR_SIZE_64 MPU_RASR_SIZE(5U)
+#define MPU_RASR_SIZE_128 MPU_RASR_SIZE(6U)
+#define MPU_RASR_SIZE_256 MPU_RASR_SIZE(7U)
+#define MPU_RASR_SIZE_512 MPU_RASR_SIZE(8U)
+#define MPU_RASR_SIZE_1K MPU_RASR_SIZE(9U)
+#define MPU_RASR_SIZE_2K MPU_RASR_SIZE(10U)
+#define MPU_RASR_SIZE_4K MPU_RASR_SIZE(11U)
+#define MPU_RASR_SIZE_8K MPU_RASR_SIZE(12U)
+#define MPU_RASR_SIZE_16K MPU_RASR_SIZE(13U)
+#define MPU_RASR_SIZE_32K MPU_RASR_SIZE(14U)
+#define MPU_RASR_SIZE_64K MPU_RASR_SIZE(15U)
+#define MPU_RASR_SIZE_128K MPU_RASR_SIZE(16U)
+#define MPU_RASR_SIZE_256K MPU_RASR_SIZE(17U)
+#define MPU_RASR_SIZE_512K MPU_RASR_SIZE(18U)
+#define MPU_RASR_SIZE_1M MPU_RASR_SIZE(19U)
+#define MPU_RASR_SIZE_2M MPU_RASR_SIZE(20U)
+#define MPU_RASR_SIZE_4M MPU_RASR_SIZE(21U)
+#define MPU_RASR_SIZE_8M MPU_RASR_SIZE(22U)
+#define MPU_RASR_SIZE_16M MPU_RASR_SIZE(23U)
+#define MPU_RASR_SIZE_32M MPU_RASR_SIZE(24U)
+#define MPU_RASR_SIZE_64M MPU_RASR_SIZE(25U)
+#define MPU_RASR_SIZE_128M MPU_RASR_SIZE(26U)
+#define MPU_RASR_SIZE_256M MPU_RASR_SIZE(27U)
+#define MPU_RASR_SIZE_512M MPU_RASR_SIZE(28U)
+#define MPU_RASR_SIZE_1G MPU_RASR_SIZE(29U)
+#define MPU_RASR_SIZE_2G MPU_RASR_SIZE(30U)
+#define MPU_RASR_SIZE_4G MPU_RASR_SIZE(31U)
+#define MPU_RASR_SRD_MASK (255U << 8U)
+#define MPU_RASR_SRD(n) ((n) << 8U)
+#define MPU_RASR_SRD_ALL (0U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB0 (1U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB1 (2U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB2 (4U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB3 (8U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB4 (16U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB5 (32U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB6 (64U << 8U)
+#define MPU_RASR_SRD_DISABLE_SUB7 (128U << 8U)
+#define MPU_RASR_ATTR_B (1U << 16U)
+#define MPU_RASR_ATTR_C (1U << 17U)
+#define MPU_RASR_ATTR_S (1U << 18U)
+#define MPU_RASR_ATTR_TEX_MASK (7U << 19U)
+#define MPU_RASR_ATTR_TEX(n) ((n) << 19U)
+#define MPU_RASR_ATTR_AP_MASK (7U << 24U)
+#define MPU_RASR_ATTR_AP(n) ((n) << 24U)
+#define MPU_RASR_ATTR_AP_NA_NA (0U << 24U)
+#define MPU_RASR_ATTR_AP_RW_NA (1U << 24U)
+#define MPU_RASR_ATTR_AP_RW_RO (2U << 24U)
+#define MPU_RASR_ATTR_AP_RW_RW (3U << 24U)
+#define MPU_RASR_ATTR_AP_RO_NA (5U << 24U)
+#define MPU_RASR_ATTR_AP_RO_RO (6U << 24U)
+#define MPU_RASR_ATTR_XN (1U << 28U)
+/** @} */
+
+/**
+ * @name Region attributes
+ * @{
+ */
+#define MPU_RASR_ATTR_STRONGLY_ORDERED (MPU_RASR_ATTR_TEX(0))
+#define MPU_RASR_ATTR_SHARED_DEVICE (MPU_RASR_ATTR_TEX(0) | MPU_RASR_ATTR_B)
+#define MPU_RASR_ATTR_CACHEABLE_WT_NWA (MPU_RASR_ATTR_TEX(0) | MPU_RASR_ATTR_C)
+#define MPU_RASR_ATTR_CACHEABLE_WB_NWA (MPU_RASR_ATTR_TEX(0) | MPU_RASR_ATTR_B | MPU_RASR_ATTR_C)
+#define MPU_RASR_ATTR_NON_CACHEABLE (MPU_RASR_ATTR_TEX(1))
+#define MPU_RASR_ATTR_CACHEABLE_WB_WA (MPU_RASR_ATTR_TEX(1) | MPU_RASR_ATTR_B | MPU_RASR_ATTR_C)
+#define MPU_RASR_ATTR_NON_SHARED_DEVICE (MPU_RASR_ATTR_TEX(2))
+/** @} */
+
+/**
+ * @name Region identifiers
+ * @{
+ */
+#define MPU_REGION_0 0U
+#define MPU_REGION_1 1U
+#define MPU_REGION_2 2U
+#define MPU_REGION_3 3U
+#define MPU_REGION_4 4U
+#define MPU_REGION_5 5U
+#define MPU_REGION_6 6U
+#define MPU_REGION_7 7U
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the MPU.
+ * @note MEMFAULENA is enabled in SCB_SHCSR.
+ *
+ * @param[in] ctrl MPU control modes as defined in @p MPU_CTRL register,
+ * the enable bit is enforced
+ *
+ * @api
+ */
+#define mpuEnable(ctrl) { \
+ MPU->CTRL = ((uint32_t)ctrl) | MPU_CTRL_ENABLE; \
+ SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; \
+}
+
+/**
+ * @brief Disables the MPU.
+ * @note MEMFAULENA is disabled in SCB_SHCSR.
+ *
+ * @api
+ */
+#define mpuDisable() { \
+ SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; \
+ MPU->CTRL = 0; \
+}
+
+/**
+ * @brief Configures an MPU region.
+ *
+ * @param[in] region the region number
+ * @param[in] address start address of the region, note, there are alignment
+ * constraints
+ * @param[in] attribs attributes mask as defined in @p MPU_RASR register
+ *
+ * @api
+ */
+#define mpuConfigureRegion(region, addr, attribs) { \
+ MPU->RNR = ((uint32_t)region); \
+ MPU->RBAR = ((uint32_t)addr); \
+ MPU->RASR = ((uint32_t)attribs); \
+}
+
+/**
+ * @brief Changes an MPU region base address.
+ *
+ * @param[in] region the region number
+ * @param[in] address start address of the region, note, there are alignment
+ * constraints
+ *
+ * @api
+ */
+#define mpuSetRegionAddress(region, addr) { \
+ MPU->RNR = ((uint32_t)region); \
+ MPU->RBAR = ((uint32_t)addr); \
+}
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MPU_H */
+
+#endif /* MPUV7M_H */
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/nvic.c b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/nvic.c new file mode 100644 index 0000000..b30c564 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/nvic.c @@ -0,0 +1,114 @@ +/*
+ 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 common/ARMCMx/nvic.c
+ * @brief Cortex-Mx NVIC support code.
+ *
+ * @addtogroup COMMON_ARMCMx_NVIC
+ * @{
+ */
+
+#include "hal.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Sets the priority of an interrupt handler and enables it.
+ *
+ * @param[in] n the interrupt number
+ * @param[in] prio the interrupt priority
+ */
+void nvicEnableVector(uint32_t n, uint32_t prio) {
+
+#if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC)
+ NVIC->IP[_IP_IDX(n)] = (NVIC->IP[_IP_IDX(n)] & ~(0xFFU << _BIT_SHIFT(n))) |
+ (NVIC_PRIORITY_MASK(prio) << _BIT_SHIFT(n));
+#else
+ NVIC->IP[n] = NVIC_PRIORITY_MASK(prio);
+#endif
+ NVIC->ICPR[n >> 5U] = 1U << (n & 0x1FU);
+ NVIC->ISER[n >> 5U] = 1U << (n & 0x1FU);
+}
+
+/**
+ * @brief Disables an interrupt handler.
+ *
+ * @param[in] n the interrupt number
+ */
+void nvicDisableVector(uint32_t n) {
+
+ NVIC->ICER[n >> 5U] = 1U << (n & 0x1FU);
+#if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC)
+ NVIC->IP[_IP_IDX(n)] = NVIC->IP[_IP_IDX(n)] & ~(0xFFU << _BIT_SHIFT(n));
+#else
+ NVIC->IP[n] = 0U;
+#endif
+}
+
+/**
+ * @brief Changes the priority of a system handler.
+ *
+ * @param[in] handler the system handler number
+ * @param[in] prio the system handler priority
+ */
+void nvicSetSystemHandlerPriority(uint32_t handler, uint32_t prio) {
+
+ osalDbgCheck(handler < 12U);
+
+#if defined(__CORE_CM0_H_GENERIC)
+ SCB->SHP[_SHP_IDX(handler)] = (SCB->SHP[_SHP_IDX(handler)] & ~(0xFFU << _BIT_SHIFT(handler))) |
+ (NVIC_PRIORITY_MASK(prio) << _BIT_SHIFT(handler));
+#elif defined(__CORE_CM7_H_GENERIC)
+ SCB->SHPR[handler] = NVIC_PRIORITY_MASK(prio);
+#else
+ SCB->SHP[handler] = NVIC_PRIORITY_MASK(prio);
+#endif
+}
+
+/**
+ * @brief Clears a pending interrupt source.
+ *
+ * @param[in] n the interrupt number
+ */
+void nvicClearPending(uint32_t n) {
+
+ NVIC->ICPR[n >> 5] = 1 << (n & 0x1F);
+}
+
+/** @} */
diff --git a/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/nvic.h b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/nvic.h new file mode 100644 index 0000000..88e32a3 --- /dev/null +++ b/ChibiOS_20.3.2/os/hal/ports/common/ARMCMx/nvic.h @@ -0,0 +1,88 @@ +/*
+ 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 common/ARMCMx/nvic.h
+ * @brief Cortex-Mx NVIC support macros and structures.
+ *
+ * @addtogroup COMMON_ARMCMx_NVIC
+ * @{
+ */
+
+#ifndef NVIC_H
+#define NVIC_H
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name System vectors numbers
+ * @{
+ */
+#define HANDLER_MEM_MANAGE 0 /**< MEM MANAGE vector id. */
+#define HANDLER_BUS_FAULT 1 /**< BUS FAULT vector id. */
+#define HANDLER_USAGE_FAULT 2 /**< USAGE FAULT vector id. */
+#define HANDLER_RESERVED_3 3
+#define HANDLER_RESERVED_4 4
+#define HANDLER_RESERVED_5 5
+#define HANDLER_RESERVED_6 6
+#define HANDLER_SVCALL 7 /**< SVCALL vector id. */
+#define HANDLER_DEBUG_MONITOR 8 /**< DEBUG MONITOR vector id. */
+#define HANDLER_RESERVED_9 9
+#define HANDLER_PENDSV 10 /**< PENDSV vector id. */
+#define HANDLER_SYSTICK 11 /**< SYS TCK vector id. */
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Priority level to priority mask conversion macro.
+ */
+#define NVIC_PRIORITY_MASK(prio) ((prio) << (8U - (unsigned)__NVIC_PRIO_BITS))
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void nvicEnableVector(uint32_t n, uint32_t prio);
+ void nvicDisableVector(uint32_t n);
+ void nvicSetSystemHandlerPriority(uint32_t handler, uint32_t prio);
+ void nvicClearPending(uint32_t n);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NVIC_H */
+
+/** @} */
|