第 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 应用层的控制台上。

相关推荐
ltl5 小时前
内核追踪:ftrace、kprobe、uprobe、tracepoint 生产实战
linux
·薯条大王5 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
芯片设计-曾工5 小时前
当精准脉冲遇上清晰视界——CH2205E模块与YL1621的“黄金搭档“
驱动开发·stm32·单片机·51单片机·硬件工程
caimouse6 小时前
TDI (传输驱动接口 Transport Driver Interface) 详细分析
网络协议
ZJH__GO8 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
小小、码农8 小时前
Linux进程控制:从fork到exec,手写一个简易Shell
linux·运维·服务器
不会就选b8 小时前
Linux之进程间通信(二)---模拟进程池
linux·运维·服务器
NeilYuen9 小时前
用UDP实现向DNS服务器请求IP地址
服务器·tcp/ip·udp
shengnan_wsn10 小时前
【协议】【TCP】
网络·网络协议·tcp/ip
沫璃染墨10 小时前
《从零入门Linux系统篇(十五):系统工具篇·六——GDB调试器详解:从程序执行控制到高级调试技巧》
linux·运维·服务器·c语言·c++