应用实战精解系列(六):RVB2601的ADC轮询单通道与DMA多通道采集

简介: 应用实战精解系列(六):RVB2601的ADC轮询单通道与DMA多通道采集

编辑语:

芯片开放社区(OCC)面向广大开发者推出应用实战系列内容,通过分享开发者实战开发案例,总结应用开发经验,梳理开发中的常见问题及解决方案,为后续参与的开发者提供更多参考与借鉴。

在上期内容中,我们为大家介绍了RVB2601开发板DAC的基础功能和特点,并基于此开发了一个web播放器,使大家更直观地了解DAC芯片的控制方式。本期我们将继续讲解基础开发内容,带大家了解RVB2601如何进行ADC的DMA采样。

# 前言

由于ADC没有文档介绍也没有例程,所以就只能靠着他所给的API来用,对照着PWM一步一步的来,最后还是调通了,也总结了不少技巧。

比如他所提供的API前面有static的就是他文件内部是函数,给自己调用的,到最后就剩下了几个。比如初始化的,adc通道配置的,adc开始停止的,adc模式的函数,还有给DMA用的缓冲区还有他相应的配置函数等等。

1.内部盗用的API,可以不用管他,刚开始还研究了好久。

 static void wj_adc_channel_conv_end_irq(csi_adc_t *adc)
 static void wj_adc_irqhandler(void *args)
 static csi_error_t wj_adc_start_intr(csi_adc_t *adc)
 static csi_error_t wj_adc_start_dma(csi_adc_t *adc)
 static csi_error_t wj_adc_stop_intr(csi_adc_t *adc)
 static csi_error_t wj_adc_stop_dma(csi_adc_t *adc)
 static int adc_channel_delete(uint8_t *channels, uint8_t nums, uint8_t channel)

2.ADC初始化,开始停止,通道配置,采样频率、时间,回调函数,ADC读取值等等

 csi_error_t csi_adc_init(csi_adc_t *adc, uint32_t idx)
 void csi_adc_uninit(csi_adc_t *adc)
 csi_error_t csi_adc_start(csi_adc_t *adc)
 csi_error_t csi_adc_stop(csi_adc_t *adc)
 csi_error_t csi_adc_channel_enable(csi_adc_t *adc, uint8_t ch_id, bool is_enable)
 csi_error_t csi_adc_channel_sampling_time(csi_adc_t *adc, uint8_t ch_id, uint16_t clock_num)
 csi_error_t csi_adc_sampling_time(csi_adc_t *adc, uint16_t clock_num)
 uint32_t csi_adc_freq_div(csi_adc_t *adc, uint32_t div)
 int32_t csi_adc_read(csi_adc_t *adc)
 csi_error_t csi_adc_get_state(csi_adc_t *adc, csi_state_t *state)
 uint32_t csi_adc_get_freq(csi_adc_t *adc)
 csi_error_t csi_adc_attach_callback(csi_adc_t *adc, void *callback, void *arg)
 void csi_adc_detach_callback(csi_adc_t *adc)
 csi_error_t csi_adc_start_async(csi_adc_t *adc)
 csi_error_t csi_adc_stop_async(csi_adc_t *adc)
 csi_error_t csi_adc_continue_mode(csi_adc_t *adc, bool is_enable)

3.ADC DMA相关配置函数:

 void wj_adc_dma_event_cb(csi_dma_ch_t *dma, csi_dma_event_t event, void *arg)
 csi_error_t csi_adc_set_buffer(csi_adc_t *adc, uint32_t *data, uint32_t num)
 csi_error_t csi_adc_link_dma(csi_adc_t *adc, csi_dma_ch_t *dma)

01 对adc单通道采样

创建一个ADC任务

 static void adc_task(void *arg)
 {
      csi_pin_set_mux(EXAMPLE_ADC_CH0, PA3_ADC_A1);
     csi_adc_init(&adc1, 0);
     uint32_t freq_value = csi_adc_freq_div(&adc1, 128);
     printf("get freq_value: %d\n", freq_value);
     csi_adc_sampling_time(&adc1, 2);
     csi_adc_continue_mode(&adc1, 1);//这句是连续采样,不使能只能采样一次
    csi_adc_channel_enable(&adc1, 0, true);
     while(1)
     {
         lv_task_handler();
         aos_msleep(400);
         lv_tick_inc(1);
        i = csi_adc_read(&adc1);
         printf("adc1:%d   ", i);
     }
 }

image.png

02 对adc多通道采样

那怎么用查询的方法对多通道采样呢?这个问题开始也是想了很久,因为读取adc函数就只有一个adc的句柄,这个句柄是初始化函数过来得到的,没有包含通道的相关操作。

这我就联想到了atm32sac的几种模式,就是扫描模式,多通道读取完一个自动对下一个进行读取,然后我就按照这个

image.png

    csi_adc_channel_enable(&adc1, 0, true);
    csi_adc_channel_enable(&adc1, 1, true);
    csi_adc_channel_enable(&adc1, 2, true);

注册了几个端口,连续读取三次果然是三个端口的值:

       i = csi_adc_read(&adc1);
       printf("adc1:%d  ", i);
       i = csi_adc_read(&adc1);
       printf("adc1:%d  ", i);
       i = csi_adc_read(&adc1);
       printf("adc1:%d  ", i);


结果就是依次读取那个PA3-5的adc值。

image.png

03 DMA对多通道采样

实际上我们比较多用DMA采样多通道的adc值,这样可以释放cpu也可以很好的随时读取:

我们加上DMA的配置代码

 csi_adc_set_buffer(&adc1,  buff0,  3);
 csi_adc_link_dma( &adc1, &dma1);  
 csi_adc_channel_enable(&adc1, 0, true);
 csi_adc_channel_enable(&adc1, 1, true);
 csi_adc_channel_enable(&adc1, 2, true);
 csi_adc_start_async(&adc1);
 while(1)
     {
         lv_task_handler();
         aos_msleep(400);
         lv_tick_inc(1);
            i=buff0[0];
         printf("adc1:%d   ", i);
         printf("adc1:%d mv\r\n", i * 3300 / 4095);    
        i=buff0[1];
         printf("adc1:%d   ", i);
         printf("adc1:%d mv\r\n", i * 3300 / 4095);    
 i=buff0[2];
         printf("adc1:%d   ", i);
         printf("adc1:%d mv\r\n", i * 3300 / 4095);  

image.png


相关文章
|
C语言
Verilog中generate的用法
Verilog中generate的用法
4062 1
OPENVPN双网卡路由规则
iptables -t nat   -A POSTROUTING -s 10.7.0.0/24 -d 10.18.101.0/24 -j SNAT --to-source 10.
3375 0
invalid-app-id(无效的AppID)参数问题自查方案
1.首先检查支付宝网关     沙箱环境网关为: [url]https://openapi.alipay[/url]dev.com/gateway.do     正式环境网关为: [url]https://openapi.
9145 12
|
1月前
|
存储 人工智能 API
OpenClaw一人AI企业搭建全攻略:阿里云/本地部署,集成Chief+Sub-Agent架构及多Agent操作指南
2026年,用OpenClaw搭建“一人公司”时,很多人会陷入多Agent管理的困境:记忆混乱导致战略分散、Token消耗激增、上下文污染让Agent“越界干活”——明明需要执行者,却养了一群“记忆错乱的演员”。核心问题不在于Agent数量,而在于架构设计错误。
433 0
|
2月前
|
安全 API 开发者
2026年 OpenClaw 技能生态测评:从官方源到本土化社区的选型指南
本文基于2026年3月实测,对比分析三大OpenClaw Skill获取方案:国内镜像源(CLI加速但不解决依赖)、可视化本土平台(开箱即用+API验证+安全预审)、官方源(权威但高风险,需“三步验证”)。强调安全准入与权限管控是AI Agent落地前提。
|
9月前
|
前端开发 JavaScript NoSQL
如何开发一套绩效管理(KPI)系统?(附架构图+流程图+代码参考)
本文介绍了如何构建科学有效的绩效管理(KPI)系统,帮助企业提升组织效率与员工成长。内容涵盖系统架构设计、功能模块开发、业务流程落地及实操技巧,提供架构图、流程图和核心代码参考,助力快速实现企业绩效管理数字化。
|
缓存 监控 Java
大厂性能优化的10大顶级方案 (万字图文史上最全)
本文详细介绍了大厂性能优化的10大顶奢方案,涵盖代码优化、缓存优化、异步优化、多线程优化、前端优化、微服务架构优化、硬件升级、数据库优化、过载保护优化以及度量与监控系统等方面。每部分不仅提供了理论知识,还结合实际案例和代码示例,帮助读者全面理解和应用这些优化策略。文章还特别强调了架构设计的重要性,指出架构师需要具备多方面的知识和技能,包括硬件、软件、网络协议、分布式知识等,以应对复杂的技术挑战。最后,作者尼恩分享了自己多年的经验,提供了丰富的技术资源和实战指导,助力读者在面试和工作中取得成功。
大厂性能优化的10大顶级方案 (万字图文史上最全)
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
776 1
|
存储 人工智能 物联网
端侧设备AI代理优化框架问世,领域内准确率可达97%
【7月更文挑战第30天】新框架Octo-planner提升端侧AI代理效率与准确性至97%。此框架由Nexa AI等机构合作研发,采用"Planner-Action"模式,将AI代理任务划分为规划与执行两部分,利用"Octopus"及"Phi-3 Mini"模型分别处理。通过fine-tuning技术及GPT-4辅助,实现在资源受限设备上的高性能。更多细节见论文: https://arxiv.org/pdf/2406.18082
505 1
|
机器学习/深度学习 数据挖掘 vr&ar
时间序列预测利器:Sklearn中的ARIMA与状态空间模型
【7月更文第24天】时间序列预测是数据分析和机器学习领域的一个重要分支,它致力于从历史数据中挖掘规律,预测未来的发展趋势。在Python的Scikit-learn库中,虽然直接提供的时间序列预测模型不如专门的时间序列分析库如Statsmodels或Prophet那样丰富,但Scikit-learn的强大之处在于其模型的灵活性和集成能力,尤其是状态空间模型的实现,为自定义复杂时间序列模型提供了坚实的基础。本文将介绍如何使用Scikit-learn进行时间序列预测,重点聚焦在ARIMA模型(通过Statsmodels间接实现)和状态空间模型的使用上,并通过代码示例深入解析。
1758 0