首页
/ ESP-IDF中ESP32-S3 ADC DMA中断函数卡死问题分析与解决

ESP-IDF中ESP32-S3 ADC DMA中断函数卡死问题分析与解决

2025-05-16 09:47:35作者:曹令琨Iris

问题现象描述

在使用ESP32-S3开发板配合ESP-IDF v5.3.1进行开发时,开发者遇到了ADC DMA中断回调函数异常停止的问题。具体表现为:

  1. 系统配置了ADC2用于单次测量两个输入信号
  2. 同时配置ADC1在连续模式下对另外两个输入信号进行周期性采样
  3. 在DMA中断回调函数中设置了计数器统计调用次数
  4. 系统运行后,回调函数会被随机调用若干次后完全停止工作
  5. 每次设备重启后,计数器最终停止的数值都不相同

问题根源分析

经过深入分析,这个问题主要由以下几个技术因素导致:

  1. 中断上下文限制:开发者将adc_continuous_read()函数放在了DMA中断回调函数中执行,而这个回调函数实际上是在GDMA帧结束中断(ISR)上下文中被调用的。

  2. 不安全的API调用adc_continuous_read()内部使用了xRingbufferReceiveUpTo()函数来从内部ADC连续模式环形缓冲区获取数据,这个函数不是设计用于ISR上下文的。

  3. 日志输出问题adc_continuous_read()函数内部使用了ESP_RETURN_ON_FALSE宏,该宏会在出错时通过串口输出日志信息,这在ISR中是无法正常工作的。

  4. 潜在的缓冲区处理问题:在早期版本(v5.0.7)中,开发者通过修改gdma_strategy_config_t结构体中的owner_check参数解决了类似问题,但在v5.3.1中这个解决方案不再适用。

解决方案

针对这个问题,我们提供以下几种解决方案:

方案一:修改ADC转换模式

ADC_CONV_MODEADC_CONV_SINGLE_UNIT_1改为ADC_CONV_BOTH_UNIT,这种方法简单但可能不适用于所有应用场景。

方案二:重构中断处理逻辑(推荐)

  1. 避免在ISR中执行复杂操作:将数据处理逻辑从DMA中断回调函数中移出
  2. 使用任务通知机制
    • 在中断回调中仅设置标志位或发送任务通知
    • 创建一个专门的任务来处理ADC数据
  3. 直接访问DMA缓冲区
    • 通过event_data参数直接获取DMA缓冲区数据
    • 避免使用内部环形缓冲区

方案三:自定义ADC驱动组件

对于对延迟要求极高的应用:

  1. esp_adc组件复制到项目本地组件目录
  2. 重写adc_continuous_read()函数,使其适合在ISR中使用
  3. 或者修改adc_dma_in_suc_eof_callback(),绕过FreeRTOS环形缓冲区

最佳实践建议

  1. 中断处理原则:保持ISR尽可能简短,仅执行必要的标志设置或简单数据拷贝
  2. 数据缓冲策略
    • 使用双缓冲机制减少数据处理延迟
    • 考虑使用无锁环形缓冲区提高效率
  3. 错误处理
    • 在ISR中使用轻量级的错误记录机制
    • 避免在ISR中进行任何可能阻塞的操作
  4. 性能监控
    • 添加监控机制检测DMA中断是否持续触发
    • 设置超时机制防止系统挂起

代码优化示例

以下是优化后的中断处理代码框架:

// 全局标志和缓冲区
volatile bool adc_data_ready = false;
uint8_t adc_raw_buffer[EXAMPLE_READ_LEN];

static void IRAM_ATTR adc_dma_callback(adc_continuous_handle_t handle, 
                                     const adc_continuous_evt_data_t *event_data, 
                                     void *user_data)
{
    // 仅做简单标记和数据拷贝
    adc_data_ready = true;
    memcpy(adc_raw_buffer, event_data->buf, EXAMPLE_READ_LEN);
}

void adc_task(void *pvParameters)
{
    while(1) {
        if(adc_data_ready) {
            // 处理ADC数据
            process_adc_data(adc_raw_buffer);
            adc_data_ready = false;
        }
        vTaskDelay(pdMS_TO_TICKS(1));
    }
}

通过以上优化,可以确保系统稳定运行,同时满足实时性要求。开发者应根据具体应用场景选择合适的解决方案。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
openHiTLS-examplesopenHiTLS-examples
本仓将为广大高校开发者提供开源实践和创新开发平台,收集和展示openHiTLS示例代码及创新应用,欢迎大家投稿,让全世界看到您的精巧密码实现设计,也让更多人通过您的优秀成果,理解、喜爱上密码技术。
C
47
253
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
347
381
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
871
516
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
179
263
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
131
184
kernelkernel
deepin linux kernel
C
22
5
nop-entropynop-entropy
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
7
0
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
335
1.09 K
harmony-utilsharmony-utils
harmony-utils 一款功能丰富且极易上手的HarmonyOS工具库,借助众多实用工具类,致力于助力开发者迅速构建鸿蒙应用。其封装的工具涵盖了APP、设备、屏幕、授权、通知、线程间通信、弹框、吐司、生物认证、用户首选项、拍照、相册、扫码、文件、日志,异常捕获、字符、字符串、数字、集合、日期、随机、base64、加密、解密、JSON等一系列的功能和操作,能够满足各种不同的开发需求。
ArkTS
31
0
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.08 K
0