From 897d2f30256a3de1b49b52cfc4453e4ad70838ac Mon Sep 17 00:00:00 2001 From: rotorman Date: Fri, 30 Jul 2021 22:11:43 +0200 Subject: [PATCH] Adheres to the STM32F429 reference manual (RM0090) Section 10.3.17 DMA stream configuration procedure. Before write access is permitted to numerous DMA registers, need to make sure that DMA is disabled for the stream. Disabling the stream is not instantaneous, and needs to be waited for (previous transmissions need to be finished first). Added return values to numerous functions to signal a failure. --- radio/src/hal/adc_driver.cpp | 34 +++++++++--- radio/src/hal/adc_driver.h | 8 +-- radio/src/opentx.cpp | 3 +- .../common/arm/stm32/stm32_hal_adc.cpp | 55 ++++++++++++++----- radio/src/targets/horus/board.cpp | 4 +- radio/src/targets/taranis/board.cpp | 3 +- 6 files changed, 80 insertions(+), 27 deletions(-) diff --git a/radio/src/hal/adc_driver.cpp b/radio/src/hal/adc_driver.cpp index 4b36440a3..fdeb1595b 100644 --- a/radio/src/hal/adc_driver.cpp +++ b/radio/src/hal/adc_driver.cpp @@ -67,30 +67,49 @@ uint16_t adcValues[NUM_ANALOGS] __DMA; uint16_t rtcBatteryVoltage; #endif -void adcInit(const etx_hal_adc_driver_t* driver) +bool adcInit(const etx_hal_adc_driver_t* driver) { etx_hal_adc_driver = driver; if (etx_hal_adc_driver && etx_hal_adc_driver->init) - etx_hal_adc_driver->init(); + { + if(!etx_hal_adc_driver->init()) + return false; + + return true; + } + return false; } -static void adcSingleRead() +static bool adcSingleRead() { - if (!etx_hal_adc_driver) return; + if (!etx_hal_adc_driver) + return false; if (etx_hal_adc_driver->start_conversion) - etx_hal_adc_driver->start_conversion(); + { + if (!etx_hal_adc_driver->start_conversion()) + return false; + } + else + return false; if (etx_hal_adc_driver->wait_completion) + { etx_hal_adc_driver->wait_completion(); + } + else + return false; + + return true; } -void adcRead() +bool adcRead() { uint16_t temp[NUM_ANALOGS] = { 0 }; for (int i=0; i<4; i++) { - adcSingleRead(); + if (!adcSingleRead()) + return false; for (uint8_t x=FIRST_ANALOG_ADC; xCR = DMA_SxCR_PL | ADC_DMA_SxCR_CHSEL | DMA_SxCR_MSIZE_0 | - DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC; dma_stream->PAR = CONVERT_PTR_UINT(&adc->DR); dma_stream->M0AR = CONVERT_PTR_UINT(dest); dma_stream->NDTR = nconv; + // Very high priority, 1 byte transfers, increment memory + dma_stream->CR = DMA_SxCR_PL | ADC_DMA_SxCR_CHSEL | DMA_SxCR_MSIZE_0 | + DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC; + // disable direct mode, half full FIFO dma_stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0; + return true; } -static void stm32_hal_adc_init() +static bool stm32_hal_adc_init() { adc_init_pins(); @@ -242,7 +255,8 @@ static void stm32_hal_adc_init() if (adc_def->dma_stream && adc_def->get_dma_buffer) { uint16_t* dma_buffer = adc_def->get_dma_buffer(); - adc_init_dma_stream(adc_def->adc, adc_def->dma_stream, dma_buffer, nconv); + if (!adc_init_dma_stream(adc_def->adc, adc_def->dma_stream, dma_buffer, nconv)) + return false; } } } @@ -260,6 +274,7 @@ static void stm32_hal_adc_init() sticksPwmInit(); } #endif + return true; } #define DMA_Stream0_IT_MASK (uint32_t)(DMA_LISR_FEIF0 | DMA_LISR_DMEIF0 | \ @@ -283,20 +298,32 @@ static void adc_dma_clear_flags(DMA_Stream_TypeDef * dma_stream) } } -static void adc_start_dma_conversion(ADC_TypeDef* ADCx, +static bool adc_start_dma_conversion(ADC_TypeDef* ADCx, DMA_Stream_TypeDef * dma_stream) { - dma_stream->CR &= ~DMA_SxCR_EN; // Disable DMA - ADCx->SR &= ~(uint32_t)(ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR); + // Disable DMA before continuing (see ref. manual "Stream configuration procedure") + if (!adc_disable_dma(dma_stream)) + return false; + + // Clear Interrupt flags adc_dma_clear_flags(dma_stream); + ADCx->SR &= ~(uint32_t)(ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR); + dma_stream->CR |= DMA_SxCR_EN; // Enable DMA ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; + return true; } -static void adc_disable_dma(DMA_Stream_TypeDef * dma_stream) +static bool adc_disable_dma(DMA_Stream_TypeDef * dma_stream) { - dma_stream->CR &= ~DMA_SxCR_EN; // Disable DMA stream + dma_stream->CR &= ~(uint32_t)DMA_SxCR_EN; + uint16_t uiTimeout = 1000; + do + { + if (--uiTimeout == 0) return false; // Timeout. Failed to disable DMA + } while (dma_stream->CR & (uint32_t)DMA_SxCR_EN); // wait until DMA enable bit gets cleared by hardware + return true; } static void adc_start_single_conversion(ADC_TypeDef* ADCx) @@ -305,7 +332,7 @@ static void adc_start_single_conversion(ADC_TypeDef* ADCx) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; } -static void stm32_hal_adc_start_read() +static bool stm32_hal_adc_start_read() { const stm32_hal_adc* adc_def = ADC_hal_def; while (adc_def->adc) { @@ -314,8 +341,9 @@ static void stm32_hal_adc_start_read() nconv = adc_def->get_nconv(); if (nconv > 0) { if (adc_def->dma_stream && adc_def->get_dma_buffer) { - adc_start_dma_conversion(adc_def->adc, adc_def->dma_stream); - } else if (nconv == 1){ + if (!adc_start_dma_conversion(adc_def->adc, adc_def->dma_stream)) + return false; + } else if (nconv == 1) { adc_start_single_conversion(adc_def->adc); } } @@ -323,6 +351,7 @@ static void stm32_hal_adc_start_read() // move to next ADC definition adc_def++; } + return true; } static void stm32_hal_adc_wait_completion() diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index b192cdda8..f3d10e507 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -200,7 +200,9 @@ void boardInit() } #endif - adcInit(&stm32_hal_adc_driver); + if (!adcInit(&stm32_hal_adc_driver)) + TRACE("adcInit failed"); + lcdInit(); backlightInit(); diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index c85907b2e..db8d4cebb 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -162,7 +162,8 @@ void boardInit() } #endif - adcInit(&stm32_hal_adc_driver); + if (!adcInit(&stm32_hal_adc_driver)) + TRACE("adcInit failed"); lcdInit(); // delaysInit() must be called before audioInit(); init2MhzTimer();