You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NUCLEO-144 STM32H723ZG开发板ADC3+DMA模式无法更新采样值(轮询模式正常)

NUCLEO-144 STM32H723ZG开发板ADC3+DMA模式无法更新采样值(轮询模式正常)

看起来你已经把轮询模式调通了,DMA模式却一直读0,这种情况我之前在H7系列上也碰到过几次,大概率是参数不匹配、DMA配置细节或者H7特有的Cache/MPU问题导致的,咱们一步步排查:

1. 先修正代码里最明显的参数不匹配问题

你设置的是8位ADC分辨率,但目前的DMA调用和变量定义存在逻辑冲突:

  • 你用了单个uint32_t adc_val变量,却传了2作为转换次数给HAL_ADC_Start_DMA——这个函数的第三个参数是转换次数,不是字节数。单个32位变量存2次8位采样值会导致地址越界,DMA根本没法正确写入数据。
  • 8位分辨率的ADC采样值应该用uint8_t类型存储,建议改成数组:
    /* USER CODE BEGIN PV */
    uint8_t adc_buff[2] = {0}; // 对应2次8位采样
    /* USER CODE END PV */
    
    然后修改DMA启动代码:
    HAL_ADC_Start_DMA(&hadc3, (uint32_t*)adc_buff, 2);
    
    这里强制转成uint32_t*是因为HAL库的函数参数要求,它会自动根据你配置的ADC分辨率处理数据宽度。

2. 检查DMA配置的关键细节

打开MX_DMA_Init()函数,确认以下几个核心配置项:

  • 内存地址递增必须开启:因为你要存储多个采样值,需要让DMA每次写完一个值后自动跳到下一个内存地址,配置里要确保hdma_adc3.Init.MemInc = DMA_MINC_ENABLE;
  • 数据对齐匹配8位分辨率:
    hdma_adc3.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_adc3.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    
  • 模式选择:连续采样用循环模式:如果你的需求是持续采样,把hdma_adc3.Init.Mode = DMA_CIRCULAR;,单次模式下DMA完成2次转换后就会停止,不会自动继续采样。
  • DMA请求通道对应ADC3:确认hdma_adc3.Init.Request = DMA_REQUEST_ADC3;,H7系列的外设DMA请求通道不能错配。

3. 确认ADC的DMA相关配置

打开MX_ADC3_Init(),检查这两个关键配置是否开启:

hadc3.Init.ContinuousConvMode = ENABLE; // 开启连续转换模式,否则ADC只采样一次
hadc3.Init.DMAContinuousRequests = ENABLE; // 允许ADC持续向DMA发送请求

这两个选项没开的话,ADC不会持续触发DMA传输,自然读不到新数据。

4. 解决H7特有的Cache一致性问题

STM32H7带Data Cache,如果你的变量存在Cacheable的内存区域,DMA写入新值后,CPU读的还是Cache里的旧初始值0,这是H7系列的常见坑。解决方法二选一:

  • 把采样变量放到非Cache内存区域,用属性声明:
    uint8_t __attribute__((section("NonCacheable"))) adc_buff[2] = {0};
    
    CubeMX生成的代码一般已经配置好了D2 SRAM作为非Cache区域,直接用即可。
  • 每次读取前手动Invalidate Cache:
    while (1) {
        SCB_InvalidateDCache_by_Addr((uint32_t*)adc_buff, sizeof(adc_buff)); // 先刷新Cache
        snprintf((char*)adc_buff, sizeof(adc_buff), "%d", adc_buff[0]); // 读取第一个采样值
        adc_buff[3] = '\n';
        HAL_UART_Transmit(&huart3, adc_buff, 4, HAL_MAX_DELAY);
        HAL_Delay(1000);
    }
    

5. 加个中断回调确认DMA是否在工作

你可以实现ADC转换完成的回调函数,验证DMA是否真的在传输数据:

/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC3)
    {
        // 可以在这里加个LED翻转,或者设置一个全局标志
        static uint8_t transfer_flag = 0;
        transfer_flag = 1;
    }
}
/* USER CODE END 4 */

如果主循环里能读到这个标志被置1,说明DMA已经在工作了,剩下的就是Cache或者数据读取的问题。

先按上面的步骤调整,尤其是前3步,应该能解决你的问题——我之前碰到的类似情况,大多是参数不匹配或者Cache的锅。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:50:28