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类型存储,建议改成数组:
然后修改DMA启动代码:/* USER CODE BEGIN PV */ uint8_t adc_buff[2] = {0}; // 对应2次8位采样 /* USER CODE END PV */
这里强制转成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内存区域,用属性声明:
CubeMX生成的代码一般已经配置好了D2 SRAM作为非Cache区域,直接用即可。uint8_t __attribute__((section("NonCacheable"))) adc_buff[2] = {0}; - 每次读取前手动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
相关产品推荐
相关产品推荐

