# thirdparty_rpmsg_lite **Repository Path**: litechaos/thirdparty_rpmsg_lite ## Basic Information - **Project Name**: thirdparty_rpmsg_lite - **Description**: 用于小型MCU的RPMsg实现。 - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: litechaos - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-02-02 - **Last Updated**: 2024-10-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [![Version](https://img.shields.io/github/v/release/nxp-mcuxpresso/rpmsg-lite)](https://github.com/nxp-mcuxpresso/rpmsg-lite/releases/latest) [![Contributors](https://img.shields.io/github/contributors/nxp-mcuxpresso/rpmsg-lite)](https://github.com/nxp-mcuxpresso/rpmsg-lite/graphs/contributors) [![Issues](https://img.shields.io/github/issues/nxp-mcuxpresso/rpmsg-lite)](https://github.com/nxp-mcuxpresso/rpmsg-lite/issues) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/nxp-mcuxpresso/rpmsg-lite/pulls) RPMsg-Lite组件 =============== 本文档描述了RPMsg-lite组件, 它是远程处理器消息传递(RPMsg)协议的轻量级实现. RPMsg协议定义了一个标准的二进制接口, 用于异构多核系统中多个核之间的通信. 与开放非对称多处理(OpenAMP)框架(https://github.com/OpenAMP/open-amp)的RPMsg实现相比, RPMsg-Lite减少了代码大小, 简化了API, 并改进了模块化。在较小的基于Cortex-M0+的系统上,建议 使用RPMsg-Lite. RPMsg-Lite是由NXP Semiconductors开发的开源组件, 并在兼容BSD许可下发布. 有关进一步的文档,请参阅doxygen文档: https://nxpmcuxpresso.github.io/rpmsg-lite/ # 创建RPMsg-Lite的动机 开发RPMsg-Lite有多种原因. 一个原因是需要较小的RPMsg协议兼容通信组件的占用空间, 另一个原因是 OpenAMP RPMsg实现的广泛API的简化. RPMsg协议没有文档化, 它的唯一定义是由Linux内核和传统的OpenAMP实现给出的. RPMsg-lite改变了这一点, 它是一个标准化协议,允许多个不同的实现共存, 并且仍然相互兼容. 基于MCU的小型系统通常不实现动态内存分配. 在RPMsg-Lite中创建静态API可以再次减少资源使用. 动态分配不仅增加了5KB的代码大小, 而且通信速度更慢, 不太确定, 这是动态内存引入的特性. 下表显示了OpenAMP RPMsg实现和新的RPMsg-Lite实现之间的一些粗略比较数据: | 组件/配置 | Flash[B] | RAM[B] | |---------------------|----------|--------| |OpenAMP RPMsg (参考) | 5547 | 456+ | |RPMsg-Lite/动态API | 3462 | 56+ | |相对偏差[%] | ~62.4% | ~12.3% | |RPMsg-Lite/静态API | 2926 | 352 | |相对偏差[%] | ~52.7% | ~77.2% | # 实现 RPMsg-Lite的实现可以分为三个子组件, 其中两个是可选的. 核心组件位于rpmsg_lite.c. 两个可选组件用于实现阻塞接收API(在rpmsg_queue.c)和动态“命名”端点创建和删除公告服务 (在rpmsg_ns.c). 实际的“媒体访问”层在virtqueue.c中实现, 这是与OpenAMP实现共享的少数文件之一. 这一层 主要定义共享内存模型, 并在内部定义使用的组件, 如vring或virtqueue. 移植层分为两个子层: 环境层和平台层. 第一个子层将分别为每个环境实现. (裸机环境已经存在, 实现在 rpmsg_env_bm.c, FreeRTOS环境实现在rpmsg_env_freertos.c等)目标应用项目 中只包含与所使用环境匹配的源文件. 第二个子层在rpmsg_platform.c中实现, 主要定义了中断 启用、禁用和触发的低层函数. 具体情况如下图所示: ![RPMsg-Lite架构](./doxygen/images/rpmsg_lite_arch.png) ## RPMsg-Lite核心子组件 这个子组件实现了一个阻塞发送API和基于回调的接收API. RPMsg协议是传输层的一部分. 这是通过使用 所谓的端点实现的. 每个端点可以被分配一个不同的接收回调函数. 然而, 重要的是要注意回调是在当前 设计的中断环境中执行的. 因此, 不鼓励在回调中执行某些操作, 如内存分配. 下图显示了RPMsg在类似 ISO/OSI的分层模型中的作用: ![RPMsg ISO/OSI分层模型](./doxygen/images/rpmsg_isoosi.png) ## Queue子组件(可选) 这个子组件是可选的, 需要在环境移植层实现env_*_queue()函数. 它使用阻塞方式接收API, 这在RTOS 环境中很常见. 它同时支持复制和不复制阻塞接收功能. ## 名称服务子组件(可选) 这个子组件是名称服务的最小实现, 它存在于RPMsg的Linux内核实现中. 它允许通信节点发送关于“名称” 端点(换句话说,通道)创建或删除的通知, 并在应用程序回调中采取用户定义的任何操作来接收这些通知. 用于接收名称服务通知的端点地址被固定为53(0x35). # 使用 应用程序应该将/rpmsg_lite/lib/include目录放到include路径中, 并在应用程序中包含 rpmsg_lite.h头文件, 或者还可以选择包含rpmsg_queue.h和/或rpmsg_ns.h文件. 这两个移植子层都应该由NXP提供, 但如果你计划使用你自己的RTOS, 你所需要做的就是实现你自己的环境 层(换句话说, rpmsg_env_myrtos.c),并将其包含在项目构建中. 堆栈的初始化是通过在主端调用rpmsg_lite_master_init()和在远端调用 rpmsg_lite_remote_init()来完成的. 这个初始化函数必须在任何RPMsg-Lite API调用之前调用. 在初始化之后, 需要创建一个通信端点, 否则就无法进行通信. 这可以通过调用 rpmsg_lite_create_ept()函数来实现. 它的最后一个参数是可选的, 其中创建端点的内部上下文, 以 防RL_USE_STATIC_API选项被设置为1. 如果不是, 堆栈内部调用env_alloc()为它分配动态内存. 如果 要使用基于回调的接收, 则使用用户定义的回调数据指针将isr回调注册到每个新端点. 如果需要阻塞接收 (在RTOS环境下), 必须在调用rpmsg_lite_create_ept()之前调用rpmsg_queue_create()函数. 队列句柄作为回调数据参数传递给端点创建函数, 并将回调函数设置为rpmsg_queue_rx_cb(). 然后, 可以使用rpmsg_queue_receive()函数侦听队列对象上的传入消息. rpmsg_lite_send()函数用于向 另一端发送消息. RPMsg-Lite还为发送和接收操作实现了非复制机制. 这些方法需要在应用程序中使用时必须考虑的细节. 非复制发送机制: 这种机制允许发送消息, 而无需将数据从应用程序缓冲区复制到共享内存中的 RPMsg/virtio缓冲区. 无副本发送步骤的执行顺序如下: - 调用rpmsg_lite_alloc_tx_buffer()函数来获取virtio缓冲区, 并向应用程序提供缓冲区指针. - 将要发送的数据填充到预先分配的virtio缓冲区. 确保填充的数据不超过缓冲区大小(由 rpmsg_lite_alloc_tx_buffer()size输出参数提供). - 调用rpmsg_lite_send_nocopy()函数将消息发送到目标端点. 考虑缓存功能和virtio缓冲区对齐. 请参阅下面的rpmsg_lite_send_nocopy()函数描述. 非复制接收机制: 这种机制允许读取消息, 而不需要将数据从共享内存中的virtio缓冲区复制到应 用程序缓冲区. 非复制接收步骤的执行顺序如下: - 调用rpmsg_queue_recv_nocopy()函数来获取接收到的数据的virtio缓冲区指针. - 直接从共享内存读取接收到的数据. - 调用rpmsg_queue_nocopy_free()函数释放virtio缓冲区, 使其可用于下一次数据传输. 用户负责销毁他所创建的任何RPMsg-Lite对象, 以防进行初始化. 为此, 使用rpmsg_queue_destroy() 函数销毁队列, 使用rpmsg_lite_destroy_ept()函数销毁端点, 最后使用rpmsg_lite_deinit()函数 去初始化RPMsg-Lite核间通信堆栈. 在反向初始化队列之前, 使用队列反向初始化所有端点。否则, 您将 主动使使用的队列句柄无效, 这是不允许的. RPMsg-Lite没有在内部检查这一点, 因为它的主要目标是轻 量级. ![RPMsg-复制和非复制接口, 多个场景](./doxygen/images/rpmsg_lite_send_receive.png) # 配置选项 RPMsg-Lite可以在编译时进行配置. 默认配置定义在rpmsg_default_config.h头文件中. 用户可以 通过包含带有自定义设置的rpmsg_config.h文件来定制此配置. 下表总结了所有可能的RPMsg-Lite配置 选项. | 配置选项 | 默认值 | 使用 | |-----------------------------|-------|-----------| |RL_MS_PER_INTERVAL | (1) | 用于轮询的非阻塞API函数中的延迟(单位: 毫秒). | |RL_BUFFER_PAYLOAD_SIZE | (496) | 缓冲区有效负载的大小,它必须等于(240, 496, 1008, ...)[2^n - 16] | |RL_BUFFER_COUNT | (2) | 缓冲区的数量,它必须是2的幂(2, 4, ...) | |RL_API_HAS_ZEROCOPY | (1) | 开启/关闭API零拷贝功能. | |RL_USE_STATIC_API | (0) | 启用/禁用静态API函数(没有动态分配). | |RL_CLEAR_USED_BUFFERS | (0) | 启用/禁用在返回的空闲缓冲区池之前清除已使用的缓冲区. | |RL_USE_MCMGR_IPC_ISR_HANDLER | (0) | 当启用IPC中断由多核管理器(IPC中断路由器)管理时, 当禁用RPMsg-Lite自己管理IPC中断. | |RL_USE_ENVIRONMENT_CONTEXT | (0) | 当启用时, 环境层使用它自己的上下文. 某些环境需要(QNX)。默认值是0(没有上下文, 节省一些RAM). | |RL_DEBUG_CHECK_BUFFERS | (0) | 当启用缓冲指针传递给rpmsg_lite_send_nocopy()和rpmsg_lite_release_rx_buffer()函数(由RL_API_HAS_ZEROCOPY配置启用)时, 将检查以避免传递无效的缓冲指针. 默认值为0(禁用). 不要在RPMsg-Lite到Linux配置中使用. | |RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION | (0) | 当启用时, 每次接收到的缓冲区被消耗并放入可用缓冲区队列时, 对端都会收到通知. 在RPMsg-Lite到Linux配置中启用此选项, 以允许解除Linux阻塞发送的阻塞. 默认值为0(RPMsg-Lite到RPMsg-Lite通信). | |RL_ALLOW_CUSTOM_SHMEM_CONFIG | (0) | 它允许定义自定义共享内存配置. 并从rpmsg_config.h替换共享内存相关的全局设置, 这在多个实例并行运行但需要不同的共享内存安排(vring大小和对齐, 缓冲区大小和计数)时非常有用. 默认值为0(所有RPMsg_Lite实例使用由公共配置宏定义的相同共享内存安排). | |RL_ASSERT | 见rpmsg_default_config.h | 断言实现. | # 向RPMsg-Lite项目贡献代码 我们欢迎并鼓励社区直接向github上的RPMsg-Lite项目提交补丁. 贡献可以通过拉取请求进行管理. 在创建拉取请求之前, 应该对代码进行测试并正确格式化. ## 怎样格式化RPMsg-Lite代码 要格式化代码, 请使用谷歌开发的应用程序, 名为*clang-format*. 该工具是 [llvm](http://llvm.org/)项目的一部分. 目前, clang格式的10.0.0版本用于RPMsg-Lite项目. clang-format使用的样式设置集在`.clang-format`文件中定义. 该文件位于RPMsg-Lite目录的根 目录下, Python脚本``run_clang_format.py``可以在该目录下执行. 这个脚本执行名为 *clang-format.exe*的应用程序. 您需要在操作系统的环境路径中有此应用程序的路径, 否则需要更改 脚本. # 参考 [1] M. Novak, M. Cingel, 基于无锁共享内存的多核通信协议 --- Copyright © 2016 Freescale Semiconductor, Inc. Copyright © 2016-2023 NXP