找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2175

积分

0

好友

281

主题
发表于 10 小时前 | 查看: 1| 回复: 0

在嵌入式系统开发中,实现高速、稳定的数据采集与传输是一个常见且具有挑战性的任务。尤其在需要处理多通道、高采样率信号的场景下,对 SoC 的数据处理能力和通信链路都提出了较高要求。本文将以瑞芯微 RK3568 平台为例,探讨如何设计一个从 FPGA 通过 USB 高速采集数据,并在 Linux 端进行缓冲、存储,最终通过 WiFi 实时传输至 Windows 主机的完整方案。

首先,我们来算一笔“数据账”,明确系统需要处理的负载。假设需求为多通道(例如12通道)、1MHz 采样率、持续 10-20 秒。数据速率大致为:通道数 × 1MHz × 2字节/样本 (假设为16位或32位ADC) = 24 MB/s。总数据量则达到:24 MB/s × 20s = 480 MB。这个量级的数据对存储的实时性和 网络(尤其是 WiFi)链路的稳定性带来了考验。

SoC 端的数据接收与存储方案

RK3568 需要建立一条高效的数据链路来接收并保存来自 USB 的数据。

1. 数据接收 (USB)

  • 驱动层:通常,FPGA 会被配置为模拟一个 USB Bulk 传输设备。在 Linux 应用层,我们可以直接使用 libusb 库来读取 Bulk 端点的数据,这种方式绕过了内核的文件抽象,延迟更低,效率更高。
  • 双缓存机制:为了防止存储或网络发送线程的短暂阻塞导致 USB 数据丢包,必须在内存中开辟环形缓冲区。这是一种典型的生产者-消费者模型:
    • 线程 A(生产者):专门负责通过 USB 持续读取数据,并写入环形缓冲区。
    • 线程 B(消费者):负责从环形缓冲区取出数据,进行本地存储或网络发送。

2. 数据存储

  • 存储位置
    • RAM(临时):如果数据仅用于后续通过网络发送,可以将其临时存储在挂载为 tmpfs 内存文件系统的 /tmp 目录下。这样做读写速度极快,并且避免了频繁写入对 eMMC 等存储设备寿命的损耗。
    • eMMC/NVMe(永久):如果需要持久化保存采集的原始数据,应直接写入二进制文件(如 .bin.dat 格式)。
  • 存储格式:至关重要的一点是,不要在高速采集过程中进行任何复杂的协议封装(如转换成 JSON 或 CSV 文本格式)。应直接存储原始二进制流,这能最大限度地减少 CPU 开销,并保持最小的文件体积。

通过 WiFi 发送数据到 Windows

前面计算出的 24 MB/s 的持续带宽对普通 WiFi 是一个考验。为确保稳定,强烈建议使用 5GHz 频段(802.11ac 或 ax 协议),2.4GHz 频段通常难以维持如此高的稳定速率。

实时流传输 (Socket 编程)

这是实现高效传输的首选方法。

  1. 协议选择:使用 TCP。尽管 UDP 的传输开销更小、速度理论上更快,但它不保证数据包的顺序和可靠性。对于 ADC 采集的二进制流,丢失任何一个字节都可能导致后续所有数据解析错位,这是灾难性的。TCP 的可靠传输特性完美契合此需求。
  2. 实现逻辑
    • Windows 端:运行一个 TCP Server(可以使用 Python、C# 或 C语言 等轻松实现),监听特定端口,等待连接并接收数据。
    • RK3568 端:作为 TCP Client,在数据采集完成后(或另一个线程在采集的同时),主动向 Windows 服务器发起连接,并调用 send() 函数发送文件数据。

使用 C 语言进行 Socket 发送时,核心目标是高效率和稳定性。考虑到数据量约 480MB,应采用分块发送的方式,而非一次性读入内存。以下是一个示例代码,展示了如何分块读取文件并通过 TCP 发送:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>

#define SERVER_IP "192.168.1.100" // Windows 端的 IP 地址
#define SERVER_PORT 8888          // 与 Windows 端一致的端口
#define CHUNK_SIZE 65536          // 每次发送 64KB,提高 WiFi 吞吐效率

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("用法: %s <数据文件路径>\n", argv[0]);
        return -1;
    }

    const char *filename = argv[1];
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *buffer = malloc(CHUNK_SIZE);

    // 1. 打开数据文件
    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        perror("无法打开文件");
        return -1;
    }

    // 2. 创建 Socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket 创建失败 \n");
        return -1;
    }

    // 设置发送缓冲区大小(可选,优化 WiFi 性能)
    int sndbuf_size = 1024 * 1024; // 1MB
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(sndbuf_size));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERVER_PORT);

    // 将 IP 地址从字符串转换为二进制格式
    if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
        printf("\n 无效的地址/ 地址不支持 \n");
        return -1;
    }

    // 3. 连接 Windows 服务端
    printf("正在连接到 Windows 服务端 %s:%d...\n", SERVER_IP, SERVER_PORT);
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\n 连接失败 \n");
        return -1;
    }

    // 4. 开始分块发送数据
    printf("开始发送数据: %s\n", filename);
    size_t n;
    long total_sent = 0;

    while ((n = fread(buffer, 1, CHUNK_SIZE, fp)) > 0) {
        ssize_t sent = send(sock, buffer, n, 0);
        if (sent < 0) {
            perror("发送失败");
            break;
        }
        total_sent += sent;
        // 打印进度(每 10MB 打印一次)
        if (total_sent % (10 * 1024 * 1024) < CHUNK_SIZE) {
            printf("已发送: %.2f MB\n", (double)total_sent / (1024 * 1024));
        }
    }

    printf("发送完成,总计发送: %.2f MB\n", (double)total_sent / (1024 * 1024));

    // 5. 收尾工作
    fclose(fp);
    free(buffer);
    close(sock);

    return 0;
}

这段代码的关键点在于:

  • 分块读取与发送:使用固定大小的缓冲区(如64KB)循环读取文件并发送,避免内存耗尽。
  • 设置 Socket 缓冲区:适当调大发送缓冲区(SO_SNDBUF)有助于平滑 WiFi 传输中的波动,提升整体吞吐量。
  • 进度反馈:在发送过程中打印进度,便于监控。

总结

整个高速采集与传输 系统设计 的核心在于“分而治之”和“缓冲解耦”。通过 USB Bulk 传输、环形缓冲区、原始二进制存储和 TCP 分块流式传输的组合,可以在 RK3568 这类嵌入式平台上有效地处理数十 MB/s 级别的数据流。实际部署时,还需重点关注 WiFi 信号强度、网络干扰以及服务器端的接收处理能力,确保端到端的稳定性。

如果你对嵌入式开发、高速数据链路或网络编程有更多兴趣,欢迎到 云栈社区 与更多开发者交流探讨,获取相关的项目源码和深入的技术资料。




上一篇:静态分析实战:四种Unity游戏global-metadata加密方案逆向与解密
下一篇:苹果CEO库克接班计划浮现,硬件与AI高管或成新双核心
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-25 19:40 , Processed in 0.325732 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表