第 12 章:Linux 侧 RPMsg 用户态驱动与数据接口

通过前面几章,我们已经让 M33 在底层跑得飞快,数据也通过 HSEM 或 OpenAMP 顶到了 A35 的门口。现在,我们要解决 Linux 开发者最关心的问题:如何在应用层(User Space)优雅、稳定地拿到这些数据?

在 Linux 侧,我们通常不希望业务逻辑开发者去操作复杂的 VirtIO 寄存器,而是提供一个标准的字符设备节点 (如 /dev/rpmsg0)。


12.1 RPMsg 字符设备框架 (RPMSG_CHAR)

Linux 内核提供了一个专用的辅助驱动 rpmsg_char,它能将 M33 侧定义的 rpmsg-raw 服务映射为文件描述符。

  • M33 侧 :我们在第 10 章创建了名为 "rpmsg-raw" 的端点。

  • Linux 侧 :内核检测到该名称后,会在 /sys/class/rpmsg/ 下生成控制接口。


12.2 实战:在 Linux 终端手动激活端点

默认情况下,Linux 可能不会自动为每个端点创建 /dev 节点。我们需要在 Linux 启动后执行以下操作:

1. 找到 M33 对应的控制器目录

cd /sys/class/rpmsg/rpmsg_ctrl0

2. 创建一个本地端点,关联到 M33 的 "rpmsg-raw" 服务

格式:echo <name> <src_addr> <dst_addr>

echo "rpmsg-raw" > create_ept

3. 检查是否生成了设备文件

ls -l /dev/rpmsg0

12.3 深度实战:编写 Linux C 应用读取 IMU 数据

现在我们可以像读串口一样编写 C 语言程序。

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <string.h>

int main() {

int fd;

char buf256;

/* 1. 打开 RPMsg 设备 */

fd = open("/dev/rpmsg0", O_RDWR);

if (fd < 0) {

perror("Open /dev/rpmsg0 failed");

return -1;

}

printf("Waiting for IMU data from M33...\n");

/* 2. 阻塞读取数据 */

while (1) {

int len = read(fd, buf, sizeof(buf) - 1);

if (len > 0) {

buflen = '\0';

/* 假设数据格式是第 10 章定义的 "ACC:x,y,z;GYRO:x,y,z" */

printf("M33 Data: %s\n", buf);

}

}

close(fd);

return 0;

}

12.4 进阶:如何处理二进制结构体?

字符串解析(sprintf/sscanf)非常耗费 CPU。在工业实战中,我们通常直接传递 二进制 Raw Data。

注意: M33 是 32 位,A35 是 64 位。虽然两者都是小端模式,但结构体对齐可能不同。

/* 在 M33 和 A35 之间必须严格共享的头文件定义 */

typedef struct attribute((packed)) {

uint32_t timestamp;

int16_t accel3;

int16_t gyro3;

uint16_t checksum;

} IMU_Frame_t;

/* A35 侧读取 */

IMU_Frame_t frame;

read(fd, &frame, sizeof(IMU_Frame_t));

12.5 异步监听:使用 poll 提高效率

如果你的 Linux 应用不仅要读 M33 数据,还要处理网络、GUI 任务,那么不能死等 read。

#include <poll.h>

struct pollfd fds1;

fds0.fd = fd;

fds0.events = POLLIN;

if (poll(fds, 1, 1000) > 0) { // 1秒超时

if (fds0.revents & POLLIN) {

read(fd, buf, sizeof(buf));

}

}

12.6 避坑指南:

  • 权限问题 :默认情况下 /dev/rpmsg0 只有 root 权限。

    • 解法 :编写 udev 规则,或者在启动脚本里 chmod 666 /dev/rpmsg0。
  • 缓冲区限制 :RPMsg 默认单包上限通常是 512 字节。如果你要传高清摄像头的一帧图像,必须分包,或者改用第 11 章的无锁队列(DDR 映射)。

  • 端点冲突 :如果 Linux 端点名和 M33 端点名不一致,read 将永远阻塞。


总结: 本章我们完成了核间通讯的最后一块拼图。现在,IMU 数据已经从传感器,经过 M33 的实时采集,穿过共享内存隧道,最终稳稳地出现在了 Linux 应用层的控制台上。

相关推荐
Decay__3 小时前
05_MySQL 常用 SQL 大全 —— 诊断、管理、优化辅助 SQL 与三大系统库速查
运维·数据库·sql·mysql·架构
贞明电子5 小时前
工业三色报警灯怎么接入项目系统?开关量与RS485控制应用指南
运维·网络·微信公众平台·贞明电子
明天也要努力学习5 小时前
HTTP 协议的基本格式和 fiddler 的用法
网络协议·http·fiddler
HideF5 小时前
Linux
linux·服务器·网络
万联WANFLOW5 小时前
海外网络故障怎么排查?Cloudflare 三季度断网报告解读与 mtr 实战
运维·网络·故障分析
吠品6 小时前
智谱开源 ZCode 之后,真正的考试才开始
单片机·嵌入式硬件·1024程序员节
Chery11407 小时前
高速ADC与精密DAC怎么选?DP9230D与DP8532D应用解析
嵌入式硬件·物联网·射频工程
Ruiery7 小时前
Linux 6.6内核内存管理深度解析(十三):slab/slub 分配器
linux·运维·服务器
乌恩大侠8 小时前
从 AI-RAN 到 AI Agent:基于 NVIDIA Nemotron 构建 5G/6G 智能网络故障诊断系统
服务器·人工智能·5g·o-ru·ai-ran·电信大模型
Decay__9 小时前
04_MySQL DBA 日常运维手册 —— 会话管理、锁与阻塞、事务监控、慢查询与日志巡检
运维·数据库·sql·mysql·架构