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

相关推荐
不悔哥16 小时前
开源OV-Watch:怎么做一个智能手表
单片机·开源·嵌入式
未济16 小时前
linux 配置环境变量
linux
傲世仙尊16 小时前
目录即文件-Ext文件系统收尾篇
linux·c语言
XiHongShi201616 小时前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
虎头金猫16 小时前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
优信电子17 小时前
AIT1001 非接触式红外测温模块 STM32 驱动开发实战:从引脚到代码全解析
stm32·嵌入式·温度传感器·红外测温·非接触式测温·ait1001
_艾伦 耶格尔.18 小时前
进程间通信
linux
AI职业加油站18 小时前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
深圳老胡18 小时前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
Liuqy-0518 小时前
Linux IO编程——静态库、动态库
linux