当前位置: 首页 > news >正文

正点原子 STM32MP257 同构多核架构下的 ADC 电压采集与处理应用开发实战

在嵌入式系统中,ADC模拟电压的读取是常见的需求。如何高效、并发、且可控地完成数据采集与处理?本篇文章通过双线程分别绑定在 Linux 系统的不同 CPU 核心上,采集 /sys/bus/iio 接口的 ADC 原始值与缩放系数 scale,并在另一个核上计算真实电压值,适用于高性能、低延迟的工业控制场景。

正点原子STM32MP257开发板 ARM嵌入式Linux异核A35&M33 AI工控

正点原子 STM32MP257 同构多核架构下的 ADC 电压采集与处理应用开发实战

  • 一、背景介绍:为什么要用多核并发读取ADC?
  • 二、系统架构与源码解析
    • 1、数据采集线程(CPU0)
    • 2、数据处理线程(CPU1)
    • 3、两线程同步机制
    • 4、完整代码及使用方法
      • 1.完整代码展示
      • 2.使用方法
  • 三、应用场景与实际部署建议
    • 1、工业自动化控制
    • 2、边缘AI与信号预处理
    • 3、多任务实时系统调度
  • 四、测试效果与输出示例
  • 五、总结与拓展建议

一、背景介绍:为什么要用多核并发读取ADC?

在嵌入式 Linux 平台(如 STM32MP257、i.MX93 等)中,我们常使用工业级 ADC 进行传感器数据采集。通过内核 IIO 子系统,用户可以在 /sys/bus/iio/devices/iio:deviceX/ 目录下读取原始电压值和电压缩放因子(scale),从而计算出真实电压。

而本项目的设计目标,是实现采集线程 + 处理线程分核运行,充分利用 A核多核系统的资源,提高数据采集实时性,降低主线程阻塞风险。

二、系统架构与源码解析

该项目通过两个线程分别运行在 CPU0 和 CPU1,线程间通过互斥锁和条件变量进行数据同步:

1、数据采集线程(CPU0)

  • 绑定在 CPU0
  • 定时读取:
    • 原始 ADC值:/sys/bus/iio/devices/iio:device0/in_voltage15_raw
    • 缩放系数:/sys/bus/iio/devices/iio:device0/in_voltage_scale
  • 通过共享内存区 shared_data 和 shared_scale,将数据传给处理线程
intval=read_sysfs_int(SYSFS_ADC_PATH);floatscale=read_sysfs_float(SYSFS_ADC_SCALE);shared_data=val;shared_scale=scale;

2、数据处理线程(CPU1)

  • 绑定在 CPU1
  • 阻塞等待数据更新信号
  • 计算真实电压:voltage = val × scale × 0.001
  • 可拓展滤波、特征提取、阈值报警等算法处理
floatvoltage=val*scale*0.001;printf("处理线程: 处理 %d × %.6f x 0.001 = %.2f V\n",val,scale,voltage);

3、两线程同步机制

  • 使用 pthread_mutex_t 和 pthread_cond_t 进行数据同步,确保线程安全。
  • data_ready 标志位控制数据更新通知。

4、完整代码及使用方法

1.完整代码展示

#define_GNU_SOURCE#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include<fcntl.h>#include<string.h>#include<errno.h>#include<sched.h>#defineSYSFS_ADC_PATH"/sys/bus/iio/devices/iio:device0/in_voltage15_raw"#defineSYSFS_ADC_SCALE"/sys/bus/iio/devices/iio:device0/in_voltage_scale"#defineACQ_INTERVAL_US500000// 500 msstaticintshared_data=0;staticfloatshared_scale=0.0f;staticintdata_ready=0;staticpthread_mutex_tdata_lock=PTHREAD_MUTEX_INITIALIZER;staticpthread_cond_tdata_cond=PTHREAD_COND_INITIALIZER;staticvoidbind_thread_to_cpu(pthread_ttid,intcpu){cpu_set_tcpuset;CPU_ZERO(&cpuset);CPU_SET(cpu,&cpuset);if(pthread_setaffinity_np(tid,sizeof(cpuset),&cpuset)!=0){fprintf(stderr,"警告:无法将线程绑定到 CPU%d: %s\n",cpu,strerror(errno));}}staticintread_sysfs_int(constchar*path){intfd=open(path,O_RDONLY);if(fd<0)return-1;charbuf[32];ssize_tlen=read(fd,buf,sizeof(buf)-1);close(fd);if(len<=0)return-1;buf[len]='\0';returnatoi(buf);}staticfloatread_sysfs_float(constchar*path){intfd=open(path,O_RDONLY);if(fd<0)return-1.0f;charbuf[32];ssize_tlen=read(fd,buf,sizeof(buf)-1);close(fd);if(len<=0)return-1.0f;buf[len]='\0';returnatof(buf);}staticvoid*acquisition_thread(void*arg){pthread_ttid=pthread_self();bind_thread_to_cpu(tid,0);printf("采集线程绑定到 CPU0\n");while(1){intval=read_sysfs_int(SYSFS_ADC_PATH);floatscale=read_sysfs_float(SYSFS_ADC_SCALE);if(val<0||scale<=0){perror("读取ADC或Scale失败");usleep(ACQ_INTERVAL_US);continue;}pthread_mutex_lock(&data_lock);shared_data=val;shared_scale=scale;data_ready=1;pthread_cond_signal(&data_cond);pthread_mutex_unlock(&data_lock);printf("采集线程: 原始值=%d, scale=%.6f\n",val,scale);usleep(ACQ_INTERVAL_US);}returnNULL;}staticvoid*processing_thread(void*arg){pthread_ttid=pthread_self();bind_thread_to_cpu(tid,1);printf("处理线程绑定到 CPU1\n");while(1){pthread_mutex_lock(&data_lock);while(!data_ready){pthread_cond_wait(&data_cond,&data_lock);}intval=shared_data;floatscale=shared_scale;data_ready=0;pthread_mutex_unlock(&data_lock);floatvoltage=val*scale*0.001;printf("处理线程: 处理 %d × %.6f x 0.001 = %.2f V\n",val,scale,voltage);}returnNULL;}intmain(intargc,char*argv[]){pthread_ttid_acq,tid_proc;intret;ret=pthread_create(&tid_acq,NULL,acquisition_thread,NULL);if(ret){fprintf(stderr,"创建采集线程失败: %s\n",strerror(ret));return1;}ret=pthread_create(&tid_proc,NULL,processing_thread,NULL);if(ret){fprintf(stderr,"创建处理线程失败: %s\n",strerror(ret));return1;}pthread_join(tid_acq,NULL);pthread_join(tid_proc,NULL);return0;}

2.使用方法

将以上代码编辑为adc_app.c文件,在 ubuntu 系统里使用以下命令交叉编译为可执行文件即可:

source/opt/st/stm32mp2/5.0.3-snapshot/environment-setup-cortexa35-ostl-linux${CC}-oadc_app adc_app.c


最终生成的adc_app文件就是我们需要放到STM32MP257文件系统里的可执行文件。

注意事项:在STM32MP257的百度资料网盘里已经提供了交叉编译工具链的安装脚本,文件路径是“STM32MP257开发板\05、开发工具\01、出厂系统交叉编译器”,请大家可以自行去下载使用。

atk-image-openstlinux-weston-stm32mp2.rootfs-x86_64-toolchain-5.0.3-snapshot-20250115-v1.0

三、应用场景与实际部署建议

本方案适用于以下典型场景:

1、工业自动化控制

  • 实时读取传感器电压信号(如压力、温湿度、光强等)
  • 多核处理确保主线程响应不中断
  • 电压计算后可直接用于闭环 PID 控制逻辑

2、边缘AI与信号预处理

  • 采集模拟数据后可直接进行数字滤波、傅里叶变换等前处理
  • 数据处理线程也可通过 RPMsg 发送到 Cortex-M33 协处理核做进一步处理

3、多任务实时系统调度

  • 多核绑定可防止线程“漂移”,适用于带有调度器的 RT-PREEMPT 系统
  • 强化线程的确定性和性能隔离

四、测试效果与输出示例

运行后,终端将周期性打印如下信息:

说明:

  • in_voltage15_raw = 4095 表示ADC原始数值
  • scale = 0.439453 mV/LSB 是 ADC 的电压精度
  • 最终电压 = 4095* 0.439453 * 0.001 ≈ 1.8V

执行 adc_app 可执行文件后,我们用 ssh 打开 STM32MP257 的新终端,用以下指令可以查看 这个例程的调用 cpu 使用情况:

top-H-p$(pidof adc_app)


通过终端显示的消息,可以看到 adc_app 主线程在 CPU1 里使用,采集数据 和 处理数据的线程 分别在 CPU0 和 CPU1 里分别使用。

五、总结与拓展建议

通过绑定线程至特定 CPU 核心,并使用条件变量进行线程同步,我们实现了一个低延迟、高稳定性的 ADC 电压采集处理方案。它可轻松适配到任意支持 Linux 的 ARM 多核平台,推荐用于工业控制、信号处理、边缘AI等高实时场景。

后续可以拓展:

  • 将数据通过 Socket/UDP/CanOpen 发送
  • 写入共享内存供 GUI 使用
  • 增加多通道采集
  • 与 Cortex-M 核通信(RPMsg)

如果你也在做 STM32MP257 / i.MX93 / RK3588 等平台的异构核协同处理,不妨试试这种方案!有问题欢迎评论区一起探讨交流!

http://www.jsqmd.com/news/803925/

相关文章:

  • Spinach印相失效全归因,深度解析--style raw失效、seed锁定崩溃及CMYK模拟断层的底层渲染链路
  • 从零开始观测你在Taotoken上的大模型API消费明细
  • 厚街游泳培训哪家值得推荐:秒杀游泳培训绝绝子 - 17322238651
  • 2026年上海留学比较好的中介,学员满意度高成关键参考 - 速递信息
  • Simplefolio缓存策略终极指南:提升开发者个人网站加载速度的完整方案
  • 终极指南:EdgeDB内置迁移系统实现零停机数据库演进的完整方案
  • 在 Hermes Agent 项目中自定义提供商并接入聚合 API 服务
  • Linux操作系统软件编程——多线程
  • 算法题(176):three states
  • 2026年南京专业留学中介机构前十强全面解析 - 速递信息
  • 清镇名表回收技术全解析:清镇靠谱的黄金回收/清镇高价回收黄金/清镇黄金回收上门/清镇黄金回收正规/清镇黄金回收靠谱/选择指南 - 优质品牌商家
  • 2026年5月邢台启闭机/螺杆启闭机/斜拉启闭机/手电螺杆启闭机/双吊点卷扬启闭机厂家解析,认准新河县全方水工机械厂 - 2026年企业推荐榜
  • 告别串口打印!用STM32CubeMonitor实时可视化你的变量波形(附F4正弦波Demo)
  • 利用taotoken模型广场为ai应用快速进行模型选型与测试
  • 动作设计模式:HTTP API动作标准化终极指南
  • 厚街吉他培训哪家值得推荐:秒杀吉他培训 服务贴心 - 19120507004
  • Diem隐私计算:安全多方计算在区块链中的终极应用指南
  • 管理多个APIKey并设置访问控制与审计日志
  • 2026年Q2常德无人机培训专业选择核心技术维度解析:怀化无人机培训/株洲无人机培训/永州无人机培训/湘潭无人机培训/选择指南 - 优质品牌商家
  • 2026油电混合SUV推荐:可油可电可增程,一台车覆盖全场景 - 速递信息
  • 使用Node.js和Taotoken快速构建一个AI对话微服务
  • 如何为现有基于OpenAI SDK的项目无缝迁移到Taotoken聚合平台
  • 【实战篇 / ZTNA】(7.0) ❀ 从零部署:FortiClient EMS 7.0 与 FortiGate 的联动配置 ❀ 零信任网络访问
  • ComfyUI-WanVideoWrapper终极指南:3个技巧解决AI视频生成难题
  • Midjourney Ziatype印相全流程实战手册(含官方未公开--style raw适配矩阵与gamma校准表)
  • 浙江音乐学院校考培训核心技术要点与备考路径解析:浙江音乐艺考机构、浙江音乐艺考集训、杭州器乐艺考培训、杭州声乐艺考培训选择指南 - 优质品牌商家
  • RPGMZ 插件制作教程 如何保存变量值到游戏存档
  • 劝!别直接用AI写论文!深扒毕业之家和PaperRed哪个才是真降重[特殊字符]
  • 2026年北京留学中介机构对比,反馈及时哪些比较好值得关注 - 速递信息
  • 【信息科学与工程学】【管理科学】第七十篇 中国主要类型企业的交易与利益交换/利益输送模型02