Solutions for ADC+DMA Target Array Not Updating

@[toc]

Solutions for ADC+DMA Target Array Not Updating

Code Structure Optimization

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : adc_dma.c
  * @brief          : ADC with DMA implementation for STM32F7 series
  ******************************************************************************
  * @attention
  * - STM32F7 L1-cache considerations:
  *   - Enabling D-cache will cause DMA data not to update
  *   - Solutions:
  *     - Use DTCM memory (0x20000000)
  *     - Manually maintain cache consistency (SCB_InvalidateDCache_by_Addr)
  *     - Configure to write-through mode
  * - Memory address allocation:
  *   - 0x20020000 (SRAM1) requires special handling
  *   - 0x20000000 (DTCM) can be used directly
  * 
  * @author HLY
  * @version V1.0
  * @date   2023-01-01
  ******************************************************************************/

Functional Module Division

/* Includes -----------------------------------------------------------------*/
#include "adc_dma.h"
#include "adc.h"

/* Macro Definitions -------------------------------------------------------*/
#define ADC1_BUFFER_SIZE   (32*1)  // ADC1 uses 4 channels, 32 sets of data for averaging
#define ADC_VREF           3.3f    // ADC reference voltage
#define ADC_RESOLUTION     4096    // 12-bit ADC resolution

/* Memory Allocation -------------------------------------------------------*/
// 32-byte alignment (address + size), ensure L1-CACHE compatibility
ALIGN_32BYTES (uint16_t adc1_data[ADC1_BUFFER_SIZE]) 
    __attribute__((section(".ARM.__at_0x20020000")));

Core Function Implementation

/**
  * @brief  ADC DMA initialization
  * @param  None
  * @retval HAL status
  * @note   Must be called during system initialization
  */
HAL_StatusTypeDef adc_dma_init(void)
{
    return HAL_ADC_Start_DMA(&hadc1, 
                           (uint32_t *)adc1_data, 
                           ADC1_BUFFER_SIZE);
}

/**
  * @brief  Get ADC conversion value (with averaging)
  * @param  channel: Index of the channel to read
  * @retval Converted voltage value (unit: V)
  */
float get_adc_voltage(uint8_t channel)
{
    uint32_t sum = 0;
    
    // Calculate the average for the specified channel
    for(int i = channel; i < ADC1_BUFFER_SIZE; i += ADC_CHANNEL_COUNT) {
        sum += adc1_data[i];
    }
    
    uint32_t avg = sum / (ADC1_BUFFER_SIZE / ADC_CHANNEL_COUNT);
    return (avg * ADC_VREF) / ADC_RESOLUTION;
}

Cache Consistency Handling

/**
  * @brief  ADC DMA half transfer complete callback
  * @param  hadc: ADC handle pointer
  * @note   Handle cache consistency for the first half of the data
  */
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1) {
        SCB_InvalidateDCache_by_Addr(
            (uint32_t *)&adc1_data[0], 
            ADC1_BUFFER_SIZE/2);
    }
}

/**
  * @brief  ADC DMA transfer complete callback
  * @param  hadc: ADC handle pointer
  * @note   Handle cache consistency for the second half of the data
  */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1) {
        SCB_InvalidateDCache_by_Addr(
            (uint32_t *)&adc1_data[ADC1_BUFFER_SIZE/2],
            ADC1_BUFFER_SIZE/2);
    }
}

Usage Example

// Initialization example
if(adc_dma_init() != HAL_OK) {
    Error_Handler();
}

// Data reading example
float voltage = get_adc_voltage(0);  // Read channel 0
printf("Voltage: %.2fV\n", voltage);

Notes

  1. 1. Memory Allocation
  • • DTCM memory (0x20000000) can be used directly
  • • SRAM1 (0x20020000) requires manual cache maintenance
  • 2. Multi-Channel ProcessingModify macro definition<span>ADC_CHANNEL_COUNT</span> to match the actual number of channels used
  • 3. Performance Optimization
    • • Use Ping-Pong buffering to improve efficiency
    • • Consider using DMA double buffering mode
  • 4. Error HandlingIt is recommended to add the following checks:
    if(HAL_ADC_Stop_DMA(&hadc1) != HAL_OK) {
        // Error handling
    }
  • 5. CalibrationIt is recommended to perform ADC calibration during initialization:
    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  • 6. Sampling Time ConfigurationAdjust the ADC sampling clock cycle according to actual needs:
    hadc1.Init.SamplingTimeCommon = ADC_SAMPLETIME_15CYCLES;
  • This optimized version improves the following aspects:

    • • Clearer code structure
    • • More comprehensive comments
    • • Stronger error handling
    • • More flexible multi-channel support
    • • More detailed notes
    • • Better maintainability

    Leave a Comment