ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

国产ARM+FPGA异构SoC工控平台实践:从BSP到数据采集

国产ARM+FPGA异构SoC工控平台实践:从BSP到数据采集 先说个背景。今年我接了一个化工现场的数据采集项目8路4-20mA模拟量、4路开关量输入、2路继电器输出还要跑Modbus协议跟现有的DCS系统做对接。甲方一上来就一句话核心器件尽量国产。我第一反应是选型物料选了好几轮最后定了复旦微FMQL45T900核心板做主控自己画底板从拿到核心板到系统跑起来、第一路采集数据送上位机前后大概用了三周。这篇文章就是这三周的完整记录包括为什么选这颗芯片、核心板和底板的架构怎么切、BSP怎么配、设备树怎么写、驱动和业务代码怎么衔接以及我踩过的坑。内容面向正在做国产化工控平台、准备用复旦微FMQL系列核心板做产品的嵌入式工程师也适合刚接触Zynq类SoC开发、想理解BSP全流程的朋友。我会尽量把操作步骤写细你照着做大概率能少走一半弯路。1. 整体方案为什么选FMQL45T900而不是Zynq或纯MCU1.1 工控信号处理平台到底需要什么工控信号处理平台说白了就是要干三类事采数、算数、传数。采数是把现场的4-20mA电流、0-10V电压、热电偶、热电阻、开关量这些物理信号变成数字量算数是对采集到的数据进行滤波、标定、阈值判断、PID控制这类处理传数是把结果通过Modbus、CAN、工业以太网送回上位机或者DCS。这三件事分给谁干就决定了整个硬件架构的走向。如果用纯MCU比如STM32好处是开发简单、资料多、大家都会。但问题也很明显主频一般不超过几百兆跑复杂的通信协议栈加实时控制容易捉襟见肘模拟量通道一多MCU的ADC轮询根本忙不过来8路同步采样就别想了再想挂个屏幕、跑个Web配置页面Flash和RAM立刻吃紧。如果甲方后续要求加EtherCAT主站、加视觉检测纯MCU方案基本就废了。那纯FPGA行不行FPGA做并行采样和硬实时逻辑确实无敌但你要是让它在上面跑一个Modbus TCP服务、挂一个文件系统、做远程固件升级那开发量直接起飞。我在上一个项目里用纯FPGA做协议转换光是把一个TCP/IP协议栈调通就花了两周别提多痛苦。所以工控平台的合理形态一定是ARMFPGA异构架构ARM跑系统、跑协议、跑应用FPGA做高速采样、并行IO和硬实时控制。这就把选型范围缩小到了Zynq这一类SoC上。1.2 FMQL45T900在国产SoC里的位置复旦微FMQL45T900就是典型的ARMFPGA异构SoC。它PS端集成双核ARM Cortex-A9可以跑嵌入式LinuxPL端是FPGA可编程逻辑45T对应的是逻辑规模900指的是DSP Slice数量大致对标同类Zynq-7000系列中高端型号。这颗芯片最大的吸引力在于PL端逻辑资源足够做8路以上同步采样、自定义编码器接口、甚至跑一个软核做辅助控制ARM端又能轻松支撑Linux系统和Modbus、Web等应用层功能。我在选型时重点关注了几个维度。第一是供应链复旦微国产物料交期和渠道比进口芯片稳得多这在今天很多项目里比性能参数更关键第二是PS主频和DDR支持FMQL45T900带DDR3/DDR3L控制器跑Linux完全够用第三是PL端资源900个DSP Slice意味着我可以在FPGA里做多通道的FIR滤波、FFT或者给AD7606这类ADC做并行采样控制不用额外买DSP芯片第四是高速接口它带GTX收发器后续做Camera-Link或者EtherCAT主站也有富余。当然也要说实话复旦微这颗芯片的资料丰富度确实没办法和进口主流芯片比很多坑要自己趟。但正因为如此才值得把这篇文章写出来把我趟过的坑标出来。1.3 核心板加底板的开发模式做嵌入式产品板卡方案一般有三种从零画整板、买核心板自绘底板、买整板开发。从零画整板意味着DDR走线、高速信号完整性、电源时序全都要自己搞定开发周期很容易拉到三个月以上而且国产SoC的参考设计有时候还不完整风险太高。买整板开发最省事但到了做产品阶段接口、尺寸、成本都没法按自己的需求调。所以我选的是核心板自绘底板这条中间路线。核心板把最难的PS端最小系统都做好了CPU、DDR3、eMMC、QSPI Flash、电源管理这些都是高密度BGA封装、DDR信号线等长这些难啃的骨头。我做底板只需要考虑怎么引出信号、怎么调理模拟量、怎么布置接口PCB层数4层基本就能搞定。核心板和底板之间用板对板连接器或者邮票孔连接我这次用的是两个80pin的排针连接器刚好够用。这种方式特别适合工控行业的小批量、多品种、快速交付场景硬件设计周期能被压缩到两三周。2. 硬件平台搭建核心板选型与底板设计要点2.1 核心板规格和接口分配我用的核心板基本配置包括FMQL45T900主芯片、1GB DDR3、8GB eMMC、256Mbit QSPI Flash板载双路千兆PHY芯片引出一路USB、一路SD卡、两路UART、若干GTX高速对。板载以太网PHY非常关键因为工控设备离不开网络通信如果核心板上没带PHY我就得在底板上自己画又多一堆信号完整性问题。拿到核心板之后的第一件事不是画底板而是先把引脚分配理清楚。我整理了一张表把核心板引出的所有Bank、PIN、默认功能和我要接的外设对应起来引脚Bank主要引脚分配用途电平标准备注PS MIO Bank 500/501MIO0-MIO53eMMC、SD、UART、USB、Ethernet3.3V大部分被核心板占用底板上主要用UART1调试串口PL Bank 13IO_L1P/T0...AD7606采样控制、SPI通信3.3V8通道ADC数据与状态信号PL Bank 34IO_L12P/T0...开关量输入输出控制、LED3.3V光耦输入、继电器驱动PL Bank 16IO_L2P/T0...LCD显示接口预留3.3V备用触摸屏接口GTX BankGTH_TX/RX预留高速串行接口差分后续扩展EtherCAT主站、Camera-Link我建议你也动手画一张这种表画完再开始Layout不然等板子画到一半发现Bank的IO口被占满或者混用电平标准返工的痛苦是成倍的。2.2 模拟量输入通道的信号调理电路模拟量采集是整个平台的核心功能。现场来的是4-20mA电流信号和0-10V电压信号但ADC本身的输入范围通常有限所以前端必须做信号调理。我选了ADI的AD7606作采样ADC16位分辨率、8通道同步采样、支持正负5V或正负10V输入SPI接口一片正好满足8路模拟量需求。AD7606的好处是自带输入钳位保护、输入放大器、抗混叠滤波器前端电路能省不少事。对4-20mA电流信号我采用250Ω精密电阻将电流转换成1-5V电压再送进AD7606。这里有两个关键点第一采样电阻一定要用低温漂精密电阻比如0.1%精度、25ppm温漂或者更好否则温度一变化整个通道精度就崩了第二电流输入端要加TVS管和保险丝现场传感器接线经常被误操作没有保护就等着烧ADC。对0-10V电压信号我用电阻分压电路衰减到0-5V同时用运放做跟随器隔离阻抗影响分压电阻同样要求低温漂。还有一个容易忽略的点模拟地和数字地怎么处理。我这次底板用了单点接地模拟地和数字地在AD7606的地引脚附近通过磁珠连接ADC的模拟电源用LC滤波隔离避免板上DCDC开关噪声窜进来。实际测试下来16位ADC的采样噪声控制在三四百微伏以内在工控环境里足够用了。2.3 底板电源和工业隔离设计工控设备的输入电源一般是24V DC而核心板需要的电源有5V、3.3V、1.8V等DDR、PL核心、PS核心还要更低电压。我底板上用了一路宽压DCDC把9-36V输入降到5V然后接两个LDO分别得到3.3V和1.8V给IO和辅助电路核心板自己内部再二次降压给PL和PS内核供电这样电源链路层次清晰调试也好定位问题。隔离设计上我做了三处第一24V输入到DCDC之前加了防反接二极管和共模电感第二开关量输入用了光耦隔离耐压做到2.5kV以上输出继电器用了单独的继电器驱动芯片加续流二极管第三RS485和CAN这类通信接口都选了隔离型收发器。工控现场最常见的故障就是地电位差和浪涌把设备打坏隔离这一层省不得。底板Layout时还要注意一点继电器这类感性负载一定要远离模拟采样区域继电器动作瞬间会产生很大的电磁干扰可能会导致ADC采集值瞬间跳变。如果空间实在不允许至少要在Layout时把继电器驱动的地单独走和模拟地分开回流。3. 开发环境搭建从装Vivado到导出硬件描述文件3.1 工具链的版本选择和安装注意事项复旦微FMQL45T900虽然是国产芯片但它的SoC架构属于Zynq类PL端用Vivado做逻辑开发PS端用PetaLinux做系统定制这套工具链和我之前做Zynq的经验基本是通用的。工具版本上一次成功的项目不要用最新的Vivado我用的是Xilinx Vivado 2019.2配合PetaLinux 2019.2这套组合拿来做FMQL45T900的工程比较稳妥。用太新的版本有时反而会遇到器件支持文件缺失、SDK不兼容的问题。安装Vivado的时候有两个容易被坑的地方。一是安装路径不要带中文和空格不然后续跑批处理脚本很可能出莫名其妙的问题二是一定要装VCU版本或者包含SDK、PetaLinux相关组件不然导出的硬件描述文件没法在PetaLinux里用。另外建议把Vivado和PetaLinux装在同一台Linux机器上我在Ubuntu 16.04和Ubuntu 18.04上都验证过能省掉很多Windows和Linux环境相互拷贝文件的麻烦。关于FMQL45T900的器件支持需要特别留意如果你的Vivado安装列表里找不到FMQL45T900这个型号通常需要安装核心板厂商或者复旦微提供的器件支持包/board file。每个批次的核心板交付资料里一般都会带一个tools目录里面有安装说明。把支持包放到Vivado的安装目录下对应位置再重启Vivado新建工程时就可以选到这块板卡了。如果找不到直接找FAE要他们对这块支持都挺积极。我用的就是厂商提供的一版board file整体流程很顺。3.2 创建最小硬件工程并导出XSA文件Vivado里创建工程时选芯片型号或者直接选核心板board file。建好工程之后我通常会建一个Block Design把Zynq PS核加进去。在PS配置界面里有几个地方必须按实际硬件来配UART1要打开对应调试串口SD卡控制器要打开DDR配置要选择和核心板上DDR颗粒匹配的参数QSPI Flash控制器打开。这些参数错了后面Linux起来就是各种U-Boot报错。PS端配置好之后把PL端的ADC采集逻辑、GPIO控制逻辑一起加进Block Design里。AD7606的SPI通信接口挂在PL端我写了一个简单的SPI控制器IP转成AXI4-Lite接口挂在PS的GP0端口上另外分配了4个PL GPIO用于控制AD7606的复位、片选和忙状态监测。所有这些做完后先跑一遍综合实现确认没有时序问题。第一次跑的时候时钟约束记得在Create Clock里加一下AD7606的采样时钟约束不然实现时全是时序告警。生成完比特流之后File - Export Hardware把硬件描述文件导出为XSA格式老版本是HDF一定要勾选Include bitstream这样PetaLinux构建出来的启动镜像里才带FPGA配置。这个XSA文件就是软件和硬件的交接点后面PetaLinux所有操作都以它为基础。导出的文件我习惯放在工程目录下一个单独文件夹里方便BSP阶段引用。4. BSP配置完整指南从PetaLinux工程到系统启动4.1 创建PetaLinux工程并导入硬件配置PetaLinux是定制Zynq类SoC Linux系统的标准工具。首先是获取编译环境打开终端执行source /opt/petalinux/2019.2/settings.sh确认petalinux-util --version能输出版本号说明环境OK。接下来创建工程petalinux-create -t project -n fmql45t900_iot --template zynq cd fmql45t900_iot petalinux-config --get-hw-description../hardware/fmql45t900_wrapper.xsa这里有个容易踩的坑--get-hw-description指定的路径会作为后续编译时的硬件描述来源但它拷贝的是XSA文件之后如果硬件工程改了你需要重新执行这条命令覆盖旧的配置否则MIO、DDR这些PS配置不会更新。进入配置界面后重点是确认几个子菜单Subsystem AUTO Hardware Settings里的Serial、Ethernet、SD等配置项有没有根据XSA自动带出来U-Boot配置里的启动方式选SD Boot还是QSPI Boot还有Image Packaging Configuration里是否勾选UltraZed之类的外部设备这个要和你的启动环境匹配。如果板子上既有SD启动也有QSPI启动建议先确定一个主力启动方式不然每次都要拨码开关切换调试时很容易搞混。4.2 内核配置与设备树裁剪PetaLinux的Build会编译内核、U-Boot、RootFS三个大件。内核配置用petalinux-config -c kernel进入menuconfig我做的裁剪包括去掉蓝牙、Wi-Fi、触摸屏、GPU等工控用不到的驱动保留EXT4、FAT文件系统支持开启GPIO Sysfs接口用于调试、SPI设备驱动、工业IO相关支持把网络协议栈里IPv6开着但默认不启用方便后续做IPv6地址兼容。设备树是BSP里最需要细看的部分。在PetaLinux里设备树源文件在project-spec/meta-user/recipes-bsp/device-tree/files/下厂商提供的system-user.dtsi通过include引入。我在这层添加自己的外设节点比如AD7606的SPI设备描述。下面是我实际使用的简化设备树片段你结合自己的引脚连接去改/include/ system-conf.dtsi / { chosen { bootargs consolettyPS0,115200 root/dev/mmcblk0p2 rw rootwait; }; }; fpga_full { ad7606_0: ad76060 { compatible adi,ad7606; reg 0; spi-max-frequency 20000000; reset-gpios gpio0 54 0; interrupt-parent intc; interrupts 0 29 4; }; };这里要解释一下spi-max-frequency设20MHz是因为AD7606的数据手册规定SPI时钟上限大概是该频率等级设太高会偶发读错数据reset-gpios用的是PL端54号引脚这个编号怎么确定要看你在硬件设计时给AD7606复位脚分配的PL Bank引脚在XSA导出的地址和GPIO编号对应关系来决定。设备树写错GPIO编号最常见的现象就是驱动probe失败时找不到复位引脚后面排查时多看一眼这里。4.3 根文件系统配置与启动镜像生成文件系统用petalinux-config -c rootfs配置我这里选上了几个实用工具can-utils现场调试CAN总线用、openssh-server远程登录修改配置用、curl和python3留作应用层脚本开发、modbus相关库我后续自己交叉编译进应用层没有直接放rootfs里。配置完成后执行petalinux-build第一次编译时间比较长看机器配置二十分钟到一小时都有可能可以在终端开着日志去干别的事。如果内核和U-Boot改过配置petalinux-build会自动只重编受影响的部分增量编译一般在几分钟内。编译完成后生成镜像在images/linux/目录下。此时需要做的是生成BOOT.BINpetalinux-package --boot --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/fmql45t900_wrapper.bit --u-boot这一步把FSBL、FPGA比特流、U-Boot打包成一个BOOT.BIN放在SD卡第一个FAT32分区。第二个分区放rootfs这里我用petalinux-package --image --format ext4生成裸镜像再用dd写到SD卡上也可以直接把rootfs目录cp到ext4分区里两种方式都能启动。SD卡制作好之后把核心板启动模式设置为SD卡启动插上调试串口线波特率115200上电。如果你能看到U-Boot打印然后Linux内核开始解压最后出现login提示符恭喜BSP这块基本就通了。5. 信号处理功能实现从LED点亮到真实数据链路5.1 GPIO/LED例程验证系统跑通系统起来之后我习惯先做最简单的GPIO测试。PetaLinux默认内核开启了GPIO Sysfs接口可以用下面的命令快速验证PL端引脚能不能正常驱动# 先看看有哪些gpiochip ls /sys/class/gpio/ # 导出PL端LED对应的GPIO621是实际编号 echo 621 /sys/class/gpio/export echo out /sys/class/gpio/gpio621/direction echo 1 /sys/class/gpio/gpio621/value如果LED能亮能灭说明从FPGA比特流到PS端GPIO控制器再到sysfs的链路全部通了。这一步虽然很基础但能同时验证设备树里的gpio节点、PL端逻辑映射、linux驱动三件事是BSP验证里性价比最高的测试。我每次换新板子都要先做这一步就像写代码先跑个Hello World一样。LED测试通过后接着验证AD7606对应的SPI设备节点在Linux下是否注册成功cat /proc/device-tree/amba_pl0/ad76060/compatible cat /proc/interrupts | grep ad7606如果设备树写对了compatible文件内容会打印adi,ad7606中断号如果注册了/proc/interrupts里能看到ad7606这个名字和触发次数。这一步很重要因为它验证的是设备树绑定、驱动模块加载、中断控制器配置三个环节。很多BSP问题都是在这里被提前发现的比等上层应用跑起来再抓瞎好太多。5.2 基于FPGA的同步采集与中断通知AD7606的8个通道是同步采样FPGA端的状态机负责控制CONVST启动转换等BUSY引脚拉低表示转换结束然后按顺序把8个通道的数据通过SPI读出来。我FPGA里用一个AXI4-Lite接口暴露三个寄存器控制寄存器、状态寄存器、FIFO数据寄存器这样ARM端只需要轮询状态寄存器或等待中断然后批量读取FIFO里的8个通道数据。PS端的中断服务程序用一个简单字符设备驱动来实现核心逻辑大概是这样的static irqreturn_t ad7606_isr(int irq, void *dev_id) { struct ad7606_dev *dev dev_id; u32 val; val ioread32(dev-base REG_STATUS); if (val BIT_ADC_DATA_READY) { for (int ch 0; ch 8; ch) dev-ch_data[ch] ioread32(dev-base REG_FIFO_DATA); wake_up_interruptible(dev-waitq); return IRQ_HANDLED; } return IRQ_NONE; }这个驱动虽然简单但已经包含了字符设备框架、内存映射、中断注册、等待队列这几个Linux驱动的核心要素。FPGA端每秒钟产生2kHz中断8路数据每次42字节ARM端完全吃得住实测CPU占用不到5%。如果后续采样率提升到几十kHz可以把FIFO加深改成DMA搬运但工控现场4-20mA信号一般不会超过几百Hz这个架构完全够用。这里要给一个实操建议中断号一定要和设备树里irq配置对应上通常是SPI类型中断PS端的中断控制器在设备树里是intc。我最初调试时在设备树里把中断号写错了一个数导致驱动probe正常但isr永远不触发排查了很久。用cat /proc/interrupts对比实际注册的中断号和设备树配置是最快的定位方法。5.3 工控通信用Modbus TCP/RTU把数据送出去信号采出来最终要送到上位机或者DCS工业现场最通用的就是Modbus协议。Modbus的优点在于协议简单、几乎所有组态软件都支持、同时有RTU串口和TCP以太网两种形态。我用的是libmodbus开源库在Linux应用层做开发。下面是一个用C语言写的简单服务片段它每100ms从驱动节点读一次采集值经过工程量换算之后写入Modbus保持寄存器#include modbus/modbus.h #include stdio.h #include unistd.h #define SLAVE_ID 1 int main(void) { modbus_t *ctx modbus_new_tcp(0.0.0.0, 502); modbus_set_slave(ctx, SLAVE_ID); modbus_mapping_t *map modbus_mapping_new(0, 0, 16, 0); int fd_ad open(/dev/ad7606, O_RDWR); while (1) { uint16_t raw[8]; read(fd_ad, raw, sizeof(raw)); for (int ch 0; ch 8; ch) { // 工程量和原始码值换算对应4-20mA范围 map-tab_registers[ch] raw[ch] * 1000 / 32767; } modbus_receive(ctx); usleep(100000); } modbus_mapping_free(map); modbus_free(ctx); return 0; }在实际工程里这个服务还应该加上看门狗、日志、配置文件读取这些功能但核心链路就是字符设备读数据 libmodbus寄存器映射。Modbus TCP在Linux下调试起来很方便你可以在开发机上用modbus-poll或者qtmodbus工具直接连接板子的IP地址实时看寄存器数值变化。这个链路也兼容很多组态软件现场集成时能省掉很多联调麻烦。6. 调试实录BSP和硬件联调的常见坑6.1 系统启动失败排查思路BSP阶段最让人崩溃的就是上电后没有任何输出。我这次调试时遇到过一次串口完全没有打印连U-Boot都进不去。排查顺序是这样的第一步检查启动模式拨码开关是不是真的拨到了SD启动核心板的拨码开关标识可能非常小我用万用表逐脚量了一遍才确认第二步检查SD卡分区是不是FAT32且BOOT.BIN在根目录很多读卡器格式化出来的FAT32实际上有隐藏扇区问题我直接换了一张正规的class10 TF卡重新分区第三步检查XSA里的UART配置确认UART1有没有实际被分配到MIO口上。如果U-Boot能进但卡在DDR初始化多半是XSA里的DDR参数和核心板上的DDR颗粒不匹配。这种问题不要自己猜直接找核心板厂商要一份能起来工程对比DDR配置项差异。我最后就是用厂商提供的参考XSA覆盖了自己的配置问题立刻解决。核心板调试前期厂商参考设计怎么配你就怎么配千万别自作聪明去优化DDR时序参数。6.2 ADC采样数据异常的快速排查系统跑通之后ADC数据异常是下一个高频问题。现象主要有三类所有通道都是0、数值固定不变、数值乱跳。所有通道都是0先检查AD7606复位信号和电源用万用表量AVCC和VDRIVE电压是否正常数值固定不变大概率是SPI时钟或片选信号没有正确触达ADC我最开始用的是Vivado逻辑分析仪核抓PL内部信号发现片选在SPI传输中间被拉高了改成低有效保持整个传输周期就正常了数值乱跳优先怀疑信号源或者地线问题把输入端短接到地看ADC读回来是否接近0如果还跳就是Layout干扰模拟地和数字地的隔离没做好。调试ADC这类混合信号外设工具上要用逻辑分析仪至少16通道以上。我用的是24MHz采样率的小型逻辑分析仪抓SPI波形足够。抓波形的同时对比设备树里的spi-max-frequency如果波形边沿已经明显圆润就降低频率SPI这块宁可保守也不要冒进。6.3 驱动加载失败和权限管理Linux驱动跑不起来的报错通常很直白insmod出unknown symbol说明内核版本和驱动模块的版本不匹配这种只能重新用PetaLinux编译环境编译驱动。设备树节点不对时dmesg里会直接提示哪个节点probe失败按提示改就行了。另外一个小细节设备节点权限默认是root如果现场维护人员用非root账号跑应用会发现打不开/dev/ad7606。解决方法是在rootfs配置里添加一个udev规则文件把节点权限改成0666或者把采集服务设为开机自启并切换到专用账户运行。关于BSP版本管理的经验我也多说一句PetaLinux工程目录一定要纳入git管理但build/目录不要提交。改动设备树前先commit一版改乱了可以git diff看清楚自己动了什么。我这次踩过最大的坑就是设备树改了几版之后忘了记录改动原因后面出问题回滚都不知道该回滚到哪一版。这个习惯建议从一开始就养成。6.4 硬件和软件并行开发的经验买核心板自绘底板的另一个好处是软硬件可以并行推进。在底板PCB加工期间我就可以在核心板厂商提供的开发板上把PetaLinux环境、设备树、驱动框架全部调通底板回来之后把开发板上调试好的镜像直接烧到底板只需要改改设备树里对应引脚的差异大量时间就省下来了。这次项目里PCB加工的两周内我把BSP和应用层框架都搭完了底板一到三天内整机联调通过这个节奏在传统从零画板再调试的模式里是很难想象的。7. 关于资料获取和后续扩展再说几句最后再分享一点我对国产SoC开发资料获取的体会。用复旦微FMQL45T900这类国产芯片做开发最忌讳的是拿它当国外芯片来用一上来就钻英文参考手册。国产芯片厂商的技术支持渠道其实很直接核心板厂商的FAE和复旦微的论坛往往是第一手资料来源很多问题在官方FAQ里经常有人问过另外就是核心板厂商通常会提供一整套基础例程包括U-Boot、内核、设备树、简单外设驱动这套东西的价值比重写一遍高得多。我的建议是拿到板子的第一天就把厂商示例工程完整编译一遍跑通之后再开始改自己的需求比从头搭环境省力得多。这个平台后续还可以继续扩展。PL端还剩下不少逻辑资源我打算下一步加一个EtherCAT从站接口做一个国产化的运动控制IO模块Linux端再把Web配置页面做起来现场调试时直接拿浏览器改IP、校准AD通道不用再开串口终端敲命令。国产ARMFPGA异构平台在工控领域的应用才刚刚开始后面能做的方向还很多。
返回列表