From a9de22787ae09737d7122764ce984905b34bbd77 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 27 Apr 2025 19:33:04 +0300 Subject: [PATCH 1/4] STM32: ADCv2: set DDS bit only in circular mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to DS: At the end of the last DMA transfer (number of transfers configured in the DMA controller’s DMA_SxNTR register): - No new DMA request is issued to the DMA controller if the DDS bit is cleared to 0 in the ADC_CR2 register (this avoids generating an overrun error). However the DMA bit is not cleared by hardware. It must be written to 0, then to 1 to start a new transfer. - Requests can continue to be generated if the DDS bit is set to 1. This allows configuring the DMA in double-buffer circular mode. --- os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c index e1513a9b98..360e3f2e3b 100644 --- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c +++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c @@ -381,7 +381,10 @@ void adc_lld_start_conversion(ADCDriver *adcp) { 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; + cr2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_ADON; + if (grpp->circular) { + cr2 |= ADC_CR2_DDS; + } /* The start method is different dependign if HW or SW triggered, the start is performed using the method specified in the CR2 configuration.*/ From bc7b4eaa2a86bab30c3ececb47cc536c2674e354 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 27 Apr 2025 19:47:35 +0300 Subject: [PATCH 2/4] STM32: ADCv2: use DMA's FIFO --- os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c index 360e3f2e3b..4a4aff93b5 100644 --- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c +++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c @@ -197,6 +197,9 @@ void adc_lld_init(void) { ADCD1.adc = ADC1; ADCD1.dmastp = NULL; ADCD1.dmamode = STM32_DMA_CR_CHSEL(ADC1_DMA_CHANNEL) | + #if (STM32_DMA_ADVANCED == TRUE) + STM32_DMA_CR_MBURST_INCR4 | + #endif STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | @@ -210,6 +213,9 @@ void adc_lld_init(void) { ADCD2.adc = ADC2; ADCD2.dmastp = NULL; ADCD2.dmamode = STM32_DMA_CR_CHSEL(ADC2_DMA_CHANNEL) | + #if (STM32_DMA_ADVANCED == TRUE) + STM32_DMA_CR_MBURST_INCR4 | + #endif STM32_DMA_CR_PL(STM32_ADC_ADC2_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | @@ -223,6 +229,9 @@ void adc_lld_init(void) { ADCD3.adc = ADC3; ADCD3.dmastp = NULL; ADCD3.dmamode = STM32_DMA_CR_CHSEL(ADC3_DMA_CHANNEL) | + #if (STM32_DMA_ADVANCED == TRUE) + STM32_DMA_CR_MBURST_INCR4 | + #endif STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | @@ -365,6 +374,9 @@ void adc_lld_start_conversion(ADCDriver *adcp) { dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * (uint32_t)adcp->depth); dmaStreamSetMode(adcp->dmastp, mode); +#if (STM32_DMA_ADVANCED == TRUE) + dmaStreamSetFIFO(adcp->dmastp, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_HALF); +#endif dmaStreamEnable(adcp->dmastp); /* ADC setup.*/ From 0710decccaec07746569f043c3c12d7d22700083 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 28 Apr 2025 15:45:31 +0300 Subject: [PATCH 3/4] STM32: ADCv2: handle DMA FIFO errors --- os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c | 5 ++++- os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c index 4a4aff93b5..f6ee3de6fd 100644 --- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c +++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c @@ -79,6 +79,9 @@ static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { /* 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 if ((flags & STM32_DMA_ISR_FEIF) != 0) { + /* FIFO error (overrun, underrun or FIFO level error) */ + _adc_isr_error_code(adcp, ADC_ERR_DMAFIFOERROR); } else { /* It is possible that the conversion group has already be reset by the @@ -375,7 +378,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { (uint32_t)adcp->depth); dmaStreamSetMode(adcp->dmastp, mode); #if (STM32_DMA_ADVANCED == TRUE) - dmaStreamSetFIFO(adcp->dmastp, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_HALF); + dmaStreamSetFIFO(adcp->dmastp, STM32_DMA_FCR_FEIE | STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_HALF); #endif dmaStreamEnable(adcp->dmastp); diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h index 9db5da9600..3d83617cad 100644 --- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h +++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h @@ -319,8 +319,9 @@ typedef uint16_t adc_channels_num_t; */ typedef enum { ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ - ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */ - ADC_ERR_WATCHDOG = 2 /**< ADC watchdog condition. */ + ADC_ERR_DMAFIFOERROR = 1, /**< DMA FIFO error. */ + ADC_ERR_OVERFLOW = 2, /**< ADC overflow condition. */ + ADC_ERR_WATCHDOG = 3 /**< ADC watchdog condition. */ } adcerror_t; /*===========================================================================*/ From 621dc5017d3328f48e25191491dd9ac8f9009911 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 25 Jan 2025 08:17:51 +0000 Subject: [PATCH 4/4] Fixed bug #1294. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@16927 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c index f6ee3de6fd..796ef485a9 100644 --- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c +++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c @@ -401,7 +401,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { cr2 |= ADC_CR2_DDS; } - /* The start method is different dependign if HW or SW triggered, the + /* The start method is different depending 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.*/ @@ -425,8 +425,9 @@ 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); + if ((adcp->adc->CR2 & ADC_CR2_CONT) != 0U) { + adcp->adc->CR2 = 0U; + } adcp->adc->CR2 = ADC_CR2_ADON; }