@[toc]

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. Memory Allocation:
- • DTCM memory (0x20000000) can be used directly
- • SRAM1 (0x20020000) requires manual cache maintenance
<span>ADC_CHANNEL_COUNT</span> to match the actual number of channels used- • Use Ping-Pong buffering to improve efficiency
- • Consider using DMA double buffering mode
if(HAL_ADC_Stop_DMA(&hadc1) != HAL_OK) {
// Error handling
}
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
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