blob: ce19f14726a5849f286c36d75d624ed2f323e6ab [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.11"/>
<title>RPMsg-Lite User&#39;s Guide: RPMsg Component</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
$(document).ready(initResizable);
$(window).load(resizeHeight);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
$(document).ready(function() { init_search(); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="customdoxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectlogo"><img alt="Logo" src="nxp_logo_small.png"/></td>
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">RPMsg-Lite User&#39;s Guide
&#160;<span id="projectnumber">Rev. 3.1.0</span>
</div>
<div id="projectbrief">NXP Semiconductors</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.11 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<div id="navrow1" class="tabs">
<ul class="tablist">
<li class="current"><a href="index.html"><span>Main&#160;Page</span></a></li>
<li><a href="modules.html"><span>API&#160;Reference</span></a></li>
<li>
<div id="MSearchBox" class="MSearchBoxInactive">
<span class="left">
<img id="MSearchSelect" src="search/mag_sel.png"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
alt=""/>
<input type="text" id="MSearchField" value="Search" accesskey="S"
onfocus="searchBox.OnSearchFieldFocus(true)"
onblur="searchBox.OnSearchFieldFocus(false)"
onkeyup="searchBox.OnSearchFieldChange(event)"/>
</span><span class="right">
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
</span>
</div>
</li>
</ul>
</div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('index.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="header">
<div class="headertitle">
<div class="title">RPMsg Component </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>This documentation describes the RPMsg-Lite component, which is a lightweight implementation of the Remote Processor Messaging (RPMsg) protocol. The RPMsg protocol defines a standardized binary interface used to communicate between multiple cores in a heterogeneous multicore system.</p>
<p>Compared to the RPMsg implementation of the Open Asymmetric Multi Processing (OpenAMP) framework (<a href="https://github.com/OpenAMP/open-amp">https://github.com/OpenAMP/open-amp</a>), the RPMsg-Lite offers a code size reduction, API simplification, and improved modularity. On smaller Cortex-M0+ based systems, it is recommended to use RPMsg-Lite.</p>
<p>The RPMsg-Lite is an open-source component developed by NXP Semiconductors and released under the BSD-compatible license.</p>
<h1><a class="anchor" id="motivation"></a>
Motivation to create RPMsg-Lite</h1>
<p>There are multiple reasons why RPMsg-Lite was developed. One reason is the need for the small footprint of the RPMsg protocol-compatible communication component, another reason is the simplification of extensive API of OpenAMP RPMsg implementation.</p>
<p>RPMsg protocol was not documented, and its only definition was given by the Linux Kernel and legacy OpenAMP implementations. This has changed with [1] which is a standardization protocol allowing multiple different implementations to coexist and still be mutually compatible.</p>
<p>Small MCU-based systems often do not implement dynamic memory allocation. The creation of static API in RPMsg-Lite enables another reduction of resource usage. Not only does the dynamic allocation adds another 5 KB of code size, but also communication is slower and less deterministic, which is a property introduced by dynamic memory. The following table shows some rough comparison data between the OpenAMP RPMsg implementation and new RPMsg-Lite implementation:</p>
<table class="doxtable">
<tr>
<th>Component / Configuration </th><th>Flash [B] </th><th>RAM [B] </th></tr>
<tr>
<td>OpenAMP RPMsg / Release (reference) </td><td>5547 </td><td>456 + dynamic </td></tr>
<tr>
<td>RPMsg-Lite / Dynamic API, Release </td><td>3462 </td><td>56 + dynamic </td></tr>
<tr>
<td>Relative Difference [%] </td><td>~62.4% </td><td>~12.3% </td></tr>
<tr>
<td>RPMsg-Lite / Static API (no malloc), Release </td><td>2926 </td><td>352 </td></tr>
<tr>
<td>Relative Difference [%] </td><td>~52.7% </td><td>~77.2% </td></tr>
</table>
<h1><a class="anchor" id="implementation"></a>
Implementation</h1>
<p>The implementation of RPMsg-Lite can be divided into three sub-components, from which two are optional. The core component is situated in <em>rpmsg_lite.c</em>. Two optional components are used to implement a blocking receive API (in <em>rpmsg_queue.c</em>) and dynamic "named" endpoint creation and deletion announcement service (in <em>rpmsg_ns.c</em>).</p>
<p>The actual "media access" layer is implemented in <em>virtqueue.c</em>, which is one of the few files shared with the OpenAMP implementation. This layer mainly defines the shared memory model, and internally defines used components such as vring or virtqueue.</p>
<p>The porting layer is split into two sub-layers: the environment layer and the platform layer. The first sublayer is to be implemented separately for each environment. (The bare metal environment already exists and is implemented in <em>rpmsg_env_bm.c</em>, and the FreeRTOS environment is implemented in <em>rpmsg_env_freertos.c</em> etc.) Only the source file, which matches the used environment, is included in the target application project. The second sublayer is implemented in <em>rpmsg_platform.c</em> and defines low-level functions for interrupt enabling, disabling, and triggering mainly. The situation is described in the following figure:</p>
<div class="image">
<img src="rpmsg_lite_arch.png" alt="rpmsg_lite_arch.png"/>
<div class="caption">
RPMsg-Lite Architecture</div></div>
<h2><a class="anchor" id="rpmsg_lite_core"></a>
RPMsg-Lite core sub-component</h2>
<p>This subcomponent implements a blocking send API and callback-based receive API. The RPMsg protocol is part of the transport layer. This is realized by using so-called endpoints. Each endpoint can be assigned a different receive callback function. However, it is important to notice that the callback is executed in an interrupt environment in current design. Therefore, certain actions like memory allocation are discouraged to execute in the callback. The following figure shows the role of RPMsg in an ISO/OSI-like layered model:</p>
<div class="image">
<img src="rpmsg_isoosi.png" alt="rpmsg_isoosi.png"/>
<div class="caption">
RPMsg ISO/OSI Layered Model</div></div>
<h2><a class="anchor" id="rpmsg_queue"></a>
Queue sub-component (optional)</h2>
<p>This subcomponent is optional and requires implementation of the env_*_queue() functions in the environment porting layer. It uses a blocking receive API, which is common in RTOS-environments. It supports both copy and nocopy blocking receive functions.</p>
<h2><a class="anchor" id="rpmsg_nameservice"></a>
Name Service sub-component (optional)</h2>
<p>This subcomponent is a minimum implementation of the name service which is present in the Linux Kernel implementation of RPMsg. It allows the communicating node both to send announcements about "named" endpoint (in other words, channel) creation or deletion and to receive these announcement taking any user-defined action in an application callback. The endpoint address used to receive name service announcements is arbitrarily fixed to be 53 (0x35).</p>
<h1><a class="anchor" id="usage"></a>
Usage</h1>
<p>The application should put the /rpmsg_lite/lib/include directory to the include path and in the application, include either the <a class="el" href="rpmsg__lite_8h_source.html">rpmsg_lite.h</a> header file, or optionally also include the <a class="el" href="rpmsg__queue_8h_source.html">rpmsg_queue.h</a> and/or <a class="el" href="rpmsg__ns_8h_source.html">rpmsg_ns.h</a> files. Both porting sublayers should be provided for you by NXP, but if you plan to use your own RTOS, all you need to do is to implement your own environment layer (in other words, rpmsg_env_myrtos.c) and to include it in the project build.</p>
<p>The initialization of the stack is done by calling the <a class="el" href="group__rpmsg__lite.html#ga79d57a0d47c1843c96530505a92a1018" title="Initializes the RPMsg-Lite communication stack. Must be called prior to any other RPMSG lite API...">rpmsg_lite_master_init()</a> on the master side and the <a class="el" href="group__rpmsg__lite.html#ga134f3fd8e6817dd2ae80148948dee3ae" title="Initializes the RPMsg-Lite communication stack. Must be called prior to any other RPMsg-Lite API...">rpmsg_lite_remote_init()</a> on the remote side. This initialization function must be called prior to any RPMsg-Lite API call. After the init, it is wise to create a communication endpoint, otherwise communication is not possible. This can be done by calling the <a class="el" href="group__rpmsg__lite.html#gad9b5d23e549a4f2adce7a79fd932568d" title="Create a new rpmsg endpoint, which can be used for communication. ">rpmsg_lite_create_ept()</a> function. It optionally accepts a last argument, where an internal context of the endpoint is created, just in case the RL_USE_STATIC_API option is set to 1. If not, the stack internally calls env_alloc() to allocate dynamic memory for it. In case a callback-based receiving is to be used, an ISR-callback is registered to each new endpoint with user-defined callback data pointer. If a blocking receive is desired (in case of RTOS environment), the <a class="el" href="group__rpmsg__queue.html#gaf2b13335342ec06d8c264bbb6e27c88f" title="Create a RPMsg queue which can be used for blocking reception. ">rpmsg_queue_create()</a> function must be called before calling <a class="el" href="group__rpmsg__lite.html#gad9b5d23e549a4f2adce7a79fd932568d" title="Create a new rpmsg endpoint, which can be used for communication. ">rpmsg_lite_create_ept()</a>. The queue handle is passed to the endpoint creation function as a callback data argument and the callback function is set to <a class="el" href="group__rpmsg__queue.html#gaeb7cba094390762f1131884b2c7e89ce" title="This callback needs to be registered with an endpoint. ">rpmsg_queue_rx_cb()</a>. Then, it is possible to use rpmsg_queue_receive() function to listen on a queue object for incoming messages. The <a class="el" href="group__rpmsg__lite.html#ga7c1d8c5ef33a89244cf272089c9332e4" title="Sends a message contained in data field of length size to the remote endpoint with address dst...">rpmsg_lite_send()</a> function is used to send messages to the other side.</p>
<p>The RPMsg-Lite also implements no-copy mechanisms for both sending and receiving operations. These methods require specifics that have to be considered when used in an application.</p>
<p><b>no-copy-send mechanism:</b> This mechanism allows sending messages without the cost for copying data from the application buffer to the RPMsg/virtio buffer in the shared memory. The sequence of no-copy sending steps to be performed is as follows:</p><ul>
<li>Call the <a class="el" href="group__rpmsg__lite.html#ga5b7a2aee9f3824a3297b6db5ef19a1f4" title="Allocates the tx buffer for message payload. ">rpmsg_lite_alloc_tx_buffer()</a> function to get the virtio buffer and provide the buffer pointer to the application.</li>
<li>Fill the data to be sent into the pre-allocated virtio buffer. Ensure that the filled data does not exceed the buffer size (provided as the <a class="el" href="group__rpmsg__lite.html#ga5b7a2aee9f3824a3297b6db5ef19a1f4" title="Allocates the tx buffer for message payload. ">rpmsg_lite_alloc_tx_buffer()</a> <em>size</em> output parameter).</li>
<li>Call the <a class="el" href="group__rpmsg__lite.html#ga90bcc1cb74c40a6966492288cd8a3d31" title="Sends a message in tx buffer allocated by rpmsg_lite_alloc_tx_buffer() ">rpmsg_lite_send_nocopy()</a> function to send the message to the destination endpoint. Consider the cache functionality and the virtio buffer alignment. See the <a class="el" href="group__rpmsg__lite.html#ga90bcc1cb74c40a6966492288cd8a3d31" title="Sends a message in tx buffer allocated by rpmsg_lite_alloc_tx_buffer() ">rpmsg_lite_send_nocopy()</a> function description below.</li>
</ul>
<p><b>no-copy-receive mechanism:</b> This mechanism allows reading messages without the cost for copying data from the virtio buffer in the shared memory to the application buffer. The sequence of no-copy receiving steps to be performed is as follows:</p><ul>
<li>Call the <a class="el" href="group__rpmsg__queue.html#ga5b6528593ab94d2377967a1cf2ec6180" title="blocking receive function - blocking version of the received function that can be called from an RTOS...">rpmsg_queue_recv_nocopy()</a> function to get the virtio buffer pointer to the received data.</li>
<li>Read received data directly from the shared memory.</li>
<li>Call the <a class="el" href="group__rpmsg__queue.html#ga1c3cff098b9464fa89788510bda231a3" title="This function frees a buffer previously returned by rpmsg_queue_recv_nocopy(). ">rpmsg_queue_nocopy_free()</a> function to release the virtio buffer and to make it available for the next data transfer.</li>
</ul>
<p>The user is responsible for destroying any RPMsg-Lite objects he has created in case of deinitialization. In order to do this, the function <a class="el" href="group__rpmsg__queue.html#ga480a59ddeeef5f54f84cd3977efcd1ec" title="Destroy a queue and clean up. Do not destroy a queue which is registered with an active endpoint! ...">rpmsg_queue_destroy()</a> is used to destroy a queue, <a class="el" href="group__rpmsg__lite.html#gabd04a23b464f1ba3360d9970b0d09c94" title="This function deletes rpmsg endpoint and performs cleanup. ">rpmsg_lite_destroy_ept()</a> is used to destroy an endpoint and finally, <a class="el" href="group__rpmsg__lite.html#ga974c3cb2c613f24a6d951b0aead1852a" title="Deinitialized the RPMsg-Lite communication stack This function always succeeds. rpmsg_lite_init() can...">rpmsg_lite_deinit()</a> is used to deinitialize the RPMsg-Lite intercore communication stack. Deinitialize all endpoints using a queue before deinitializing the queue. Otherwise, you are actively invalidating the used queue handle, which is not allowed. RPMsg-Lite does not check this internally, since its main aim is to be lightweight.</p>
<div class="image">
<img src="rpmsg_lite_send_receive.png" alt="rpmsg_lite_send_receive.png"/>
<div class="caption">
RPMsg Lite copy and no-copy interface, multiple scenarios</div></div>
<h1><a class="anchor" id="configuration"></a>
Configuration options</h1>
<p>The RPMsg-Lite can be configured at the compile time. The default configuration is defined in the <a class="el" href="rpmsg__default__config_8h.html">rpmsg_default_config.h</a> header file. This configuration can be customized by the user by including rpmsg_config.h file with custom settings. The following table summarizes all possible RPMsg-Lite configuration options.</p>
<table class="doxtable">
<tr>
<th>Configuration option </th><th>Default value </th><th>Usage </th></tr>
<tr>
<td>RL_MS_PER_INTERVAL </td><td>(1) </td><td>Delay in milliseconds used in non-blocking API functions for polling. </td></tr>
<tr>
<td>RL_BUFFER_PAYLOAD_SIZE </td><td>(496) </td><td>Size of the buffer payload, it must be equal to (240, 496, 1008, ...) [2^n - 16] </td></tr>
<tr>
<td>RL_BUFFER_COUNT </td><td>(2) </td><td>Number of the buffers, it must be power of two (2, 4, ...) </td></tr>
<tr>
<td>RL_API_HAS_ZEROCOPY </td><td>(1) </td><td>Zero-copy API functions enabled/disabled. </td></tr>
<tr>
<td>RL_USE_STATIC_API </td><td>(0) </td><td>Static API functions (no dynamic allocation) enabled/disabled. </td></tr>
<tr>
<td>RL_CLEAR_USED_BUFFERS </td><td>(0) </td><td>Clearing used buffers before returning back to the pool of free buffers enabled/disabled. </td></tr>
<tr>
<td>RL_USE_MCMGR_IPC_ISR_HANDLER </td><td>(0) </td><td>When enabled IPC interrupts are managed by the Multicore Manager (IPC interrupts router), when disabled RPMsg-Lite manages IPC interrupts by itself. </td></tr>
<tr>
<td>RL_USE_ENVIRONMENT_CONTEXT </td><td>(0) </td><td>When enabled the environment layer uses its own context. Required for some environments (QNX). The default value is 0 (no context, saves some RAM). </td></tr>
<tr>
<td>RL_DEBUG_CHECK_BUFFERS </td><td>(0) </td><td>When enabled buffer debug checks in <a class="el" href="group__rpmsg__lite.html#ga90bcc1cb74c40a6966492288cd8a3d31" title="Sends a message in tx buffer allocated by rpmsg_lite_alloc_tx_buffer() ">rpmsg_lite_send_nocopy()</a> and <a class="el" href="group__rpmsg__lite.html#ga847cb39c655a6068107ac9840cfd7bf2" title="Releases the rx buffer for future reuse in vring. This API can be called at process context when the ...">rpmsg_lite_release_rx_buffer()</a> functions are disabled. Do not use in RPMsg-Lite to Linux configuration. </td></tr>
<tr>
<td>RL_ASSERT </td><td>see <a class="el" href="rpmsg__default__config_8h.html">rpmsg_default_config.h</a> </td><td>Assert implementation. </td></tr>
</table>
<h1><a class="anchor" id="references"></a>
References</h1>
<p>[1] M. Novak, M. Cingel, Lockless Shared Memory Based Multicore Communication Protocol</p>
<h1><a class="anchor" id="revision_history"></a>
Revision History</h1>
<p>This table summarizes revisions of this document.</p>
<table class="doxtable">
<tr>
<th>Revision number</th><th>Date </th><th>Substantive changes </th></tr>
<tr>
<td>1.0 </td><td>09/2016 </td><td>Initial release </td></tr>
<tr>
<td>2.0 </td><td>02/2017 </td><td><p class="starttd">Added macros for packed structures (compiler.h) </p>
<p>Improved interrupt handling in platform layer </p>
<p>Changed RL_BUFFER_SIZE definition </p>
<p>Fix of double initialization of vring shared data structure </p>
<p>Support for the multi-instance </p>
<p class="endtd">Simplified virtqueue.c, removing race condition </p>
</td></tr>
<tr>
<td>3.0 </td><td>08/2017 </td><td><p class="starttd">Several source files renamed to avoid conflicts with other middleware software components </p>
<p>Added user data into RPMsg Nameservice callback </p>
<p>Added the RL_CLEAR_USED_BUFFERS configuration option to allow clearing used buffers before returning back to the pool of free buffers </p>
<p class="endtd">Added the ability to use Multicore Manager (MCMGR) as the IPC interrupts router (RL_USE_MCMGR_IPC_ISR_HANDLER config) </p>
</td></tr>
<tr>
<td>4.0 </td><td>04/2018 </td><td><p class="starttd">New API <a class="el" href="group__rpmsg__queue.html#ga2d65626ac1279a50be5e1f86ed80acbf" title="This function returns the number of pending messages in the queue. ">rpmsg_queue_get_current_size()</a> </p>
<p>Fixed bug in interrupt handling for lpc5411x, lpc5410x </p>
<p class="endtd">Code adjustments based on static analysis tool findings </p>
</td></tr>
<tr>
<td>5.0 </td><td>09/2018 </td><td><p class="starttd">Align porting layers to the updated MCUXpressoSDK feature files </p>
<p class="endtd">Allow rpmsg-lite build by Keil MDK ArmClangV6 compiler </p>
</td></tr>
<tr>
<td>6.0 </td><td>04/2019 </td><td><p class="starttd">Added configuration macro RL_DEBUG_CHECK_BUFFERS </p>
<p>Several MISRA violations fixed </p>
<p>Added environment layers for QNX and Zephyr </p>
<p class="endtd">Allow environment context required for some environments (controlled by the RL_USE_ENVIRONMENT_CONTEXT configuration macro). </p>
</td></tr>
<tr>
<td>7.0 </td><td>11/2019 </td><td><p class="starttd">MISRA C-2012 violations fixed, incl. data types consolidation </p>
<p class="endtd">Code formatted. </p>
</td></tr>
<tr>
<td>8.0 </td><td>04/2020 </td><td><p class="starttd">MISRA C-2012 violations fixed (7.4) </p>
<p>Fix missing lock in rpmsg_lite_rx_callback() for QNX env </p>
<p>Correction of <a class="el" href="group__rpmsg__lite.html#structrpmsg__lite__instance">rpmsg_lite_instance</a> structure members description </p>
<p>Address -Waddress-of-packed-member warnings in GCC9 </p>
<p class="endtd">Clang update to v10.0.0, code re-formatted. </p>
</td></tr>
</table>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.8.5-->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul class="foot">
<li class="footer">Copyright 2016-2020 NXP Semiconductors. All rights reserved.
</li>
</ul>
</div>
</body>
</html>