Coder Social home page Coder Social logo

nxp-mcuxpresso / rpmsg-lite Goto Github PK

View Code? Open in Web Editor NEW
211.0 28.0 67.0 907 KB

RPMsg implementation for small MCUs

License: BSD 3-Clause "New" or "Revised" License

CSS 2.48% HTML 0.05% C 97.04% CMake 0.43%
rpmsg-lite amp multicore rpmsg-protocol openamp-rpmsg shared-memory

rpmsg-lite's Introduction

Version Contributors Issues PRs Welcome

RPMsg Component

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.

Compared to the RPMsg implementation of the Open Asymmetric Multi Processing (OpenAMP) framework (https://github.com/OpenAMP/open-amp), 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.

The RPMsg-Lite is an open-source component developed by NXP Semiconductors and released under the BSD-compatible license.

For Further documentation, please look at doxygen documentation at: https://nxp-mcuxpresso.github.io/rpmsg-lite/

Motivation to create RPMsg-Lite

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.

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.

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:

Component / Configuration Flash [B] RAM [B]
OpenAMP RPMsg / Release (reference) 5547 456 + dynamic
RPMsg-Lite / Dynamic API, Release 3462 56 + dynamic
Relative Difference [%] ~62.4% ~12.3%
RPMsg-Lite / Static API (no malloc), Release 2926 352
Relative Difference [%] ~52.7% ~77.2%

Implementation

The implementation of RPMsg-Lite can be divided into three sub-components, from which two are optional. The core component is situated in rpmsg_lite.c. Two optional components are used to implement a blocking receive API (in rpmsg_queue.c) and dynamic "named" endpoint creation and deletion announcement service (in rpmsg_ns.c).

The actual "media access" layer is implemented in virtqueue.c, 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.

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 rpmsg_env_bm.c, and the FreeRTOS environment is implemented in rpmsg_env_freertos.c etc.) Only the source file, which matches the used environment, is included in the target application project. The second sublayer is implemented in rpmsg_platform.c and defines low-level functions for interrupt enabling, disabling, and triggering mainly. The situation is described in the following figure:

RPMsg-Lite Architecture

RPMsg-Lite core sub-component

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:

RPMsg ISO/OSI Layered Model

Queue sub-component (optional)

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.

Name Service sub-component (optional)

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).

Usage

The application should put the /rpmsg_lite/lib/include directory to the include path and in the application, include either the rpmsg_lite.h header file, or optionally also include the rpmsg_queue.h and/or rpmsg_ns.h 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.

The initialization of the stack is done by calling the rpmsg_lite_master_init() on the master side and the rpmsg_lite_remote_init() 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 rpmsg_lite_create_ept() 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 rpmsg_queue_create() function must be called before calling rpmsg_lite_create_ept(). The queue handle is passed to the endpoint creation function as a callback data argument and the callback function is set to rpmsg_queue_rx_cb(). Then, it is possible to use rpmsg_queue_receive() function to listen on a queue object for incoming messages. The rpmsg_lite_send() function is used to send messages to the other side.

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.

no-copy-send mechanism: 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:

  • Call the rpmsg_lite_alloc_tx_buffer() function to get the virtio buffer and provide the buffer pointer to the application.
  • 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 rpmsg_lite_alloc_tx_buffer() size output parameter).
  • Call the rpmsg_lite_send_nocopy() function to send the message to the destination endpoint. Consider the cache functionality and the virtio buffer alignment. See the rpmsg_lite_send_nocopy() function description below.

no-copy-receive mechanism: 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:

  • Call the rpmsg_queue_recv_nocopy() function to get the virtio buffer pointer to the received data.
  • Read received data directly from the shared memory.
  • Call the rpmsg_queue_nocopy_free() function to release the virtio buffer and to make it available for the next data transfer.

The user is responsible for destroying any RPMsg-Lite objects he has created in case of deinitialization. In order to do this, the function rpmsg_queue_destroy() is used to destroy a queue, rpmsg_lite_destroy_ept() is used to destroy an endpoint and finally, rpmsg_lite_deinit() 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.

RPMsg Lite copy and no-copy interface, multiple scenarios

Examples

RPMsg_Lite multicore examples are part of NXP MCUXpressoSDK packages. Visit https://mcuxpresso.nxp.com to configure, build and download these packages. To get the board list with multicore support (RPMsg_Lite included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see

<MCUXpressoSDK_install_dir>/boards/<board_name>/multicore_examples for RPMsg_Lite multicore examples with 'rpmsg_lite_' name prefix.

Another way of getting NXP MCUXpressoSDK RPMsg_Lite multicore examples is using the mcux-sdk Github repo. Follow the description how to use the West tool to clone and update the mcuxsdk repo in readme Overview section. Once done the armgcc rpmsg_lite examples can be found in

mcuxsdk/examples/<board_name>/multicore_examples

You can use the evkmimxrt1170 as the board_name for instance. Similar to MCUXpressoSDK packages the RPMsg_Lite examples use the 'rpmsg_lite_' name prefix.

Notes

Environment layers implementation

Several environment layers are provided in lib/rpmsg_lite/porting/environment folder. Not all of them are fully tested however. Here is the list of environment layers that passed testing:

  • rpmsg_env_bm.c
  • rpmsg_env_freertos.c
  • rpmsg_env_xos.c
  • rpmsg_env_threadx.c

The rest of environment layers has been created and used in some experimental projects, it has been running well at the time of creation but due to the lack of unit testing there is no guarantee it is still fully functional.

Shared memory configuration

It is important to correctly initialize/configure the shared memory for data exchange in the application. The shared memory must be accessible from both the master and the remote core and it needs to be configured as Non-Cacheable memory. Dedicated shared memory section in liker file is also a good practise, it is recommended to use linker files from MCUXpressSDK packages for NXP devices based applications. It needs to be ensured no other application part/component is unintentionally accessing this part of memory.

Configuration options

The RPMsg-Lite can be configured at the compile time. The default configuration is defined in the rpmsg_default_config.h 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.

Configuration option Default value Usage
RL_MS_PER_INTERVAL (1) Delay in milliseconds used in non-blocking API functions for polling.
RL_BUFFER_PAYLOAD_SIZE (496) Size of the buffer payload, it must be equal to (240, 496, 1008, ...) [2^n - 16]
RL_BUFFER_COUNT (2) Number of the buffers, it must be power of two (2, 4, ...)
RL_API_HAS_ZEROCOPY (1) Zero-copy API functions enabled/disabled.
RL_USE_STATIC_API (0) Static API functions (no dynamic allocation) enabled/disabled.
RL_CLEAR_USED_BUFFERS (0) Clearing used buffers before returning back to the pool of free buffers enabled/disabled.
RL_USE_MCMGR_IPC_ISR_HANDLER (0) When enabled IPC interrupts are managed by the Multicore Manager (IPC interrupts router), when disabled RPMsg-Lite manages IPC interrupts by itself.
RL_USE_ENVIRONMENT_CONTEXT (0) When enabled the environment layer uses its own context. Required for some environments (QNX). The default value is 0 (no context, saves some RAM).
RL_DEBUG_CHECK_BUFFERS (0) When enabled buffer pointers passed to rpmsg_lite_send_nocopy() and rpmsg_lite_release_rx_buffer() functions (enabled by RL_API_HAS_ZEROCOPY config) are checked to avoid passing invalid buffer pointer. The default value is 0 (disabled). Do not use in RPMsg-Lite to Linux configuration.
RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION (0) When enabled the opposite side is notified each time received buffers are consumed and put into the queue of available buffers. Enable this option in RPMsg-Lite to Linux configuration to allow unblocking of the Linux blocking send. The default value is 0 (RPMsg-Lite to RPMsg-Lite communication).
RL_ALLOW_CUSTOM_SHMEM_CONFIG (0) It allows to define custom shared memory configuration and replacing the shared memory related global settings from rpmsg_config.h This is useful when multiple instances are running in parallel but different shared memory arrangement (vring size & alignment, buffers size & count) is required. The default value is 0 (all RPMsg_Lite instances use the same shared memory arrangement as defined by common config macros).
RL_ASSERT see rpmsg_default_config.h Assert implementation.

Contributing to the rpmsg-lite project

We welcome and encourage the community to submit patches directly to the rpmsg-lite project placed on github. Contributing can be managed via pull-requests. Before a pull-request is created the code should be tested and properly formatted.

How to format rpmsg-lite code

To format code, use the application developed by Google, named clang-format. This tool is part of the llvm project. Currently, the clang-format 10.0.0 version is used for rpmsg-lite. The set of style settings used for clang-format is defined in the .clang-format file, placed in a root of the rpmsg-lite directory where Python script run_clang_format.py can be executed. This script executes the application named clang-format.exe. You need to have the path of this application in the OS's environment path, or you need to change the script.

References

[1] M. Novak, M. Cingel, Lockless Shared Memory Based Multicore Communication Protocol


Copyright © 2016 Freescale Semiconductor, Inc. Copyright © 2016-2024 NXP

rpmsg-lite's People

Contributors

biwenli avatar flit avatar hadatko avatar mareknovaknxp avatar mcuxcibot avatar michalprincnxp avatar zhiqiang-hou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rpmsg-lite's Issues

Required shared memory size?

What is the required shared memory size for rpmsg? Would the following formula correctly express the requirements?

2 * (RL_BUFFER_COUNT * (RL_BUFFER_PAYLOAD_SIZE + 16) + vring_size(RL_BUFFER_COUNT, VRING_ALIGN))

Macro expansion bug in RL_ASSERT

The RL_ASSERT macro is defined as

#define RL_ASSERT(x)  \
    do                \
    {                 \
        if (!x)       \
            while (1) \
                ;     \
    } while (0);

in rpmsg_default_config.h.

When calling this macro with an expression as an argument like you do in https://github.com/NXPmicro/rpmsg-lite/blob/master/lib/rpmsg_lite/rpmsg_lite.c#L160, it gets expanded in the wrong way.

Instead of if(!(rpmsg_lite_dev != NULL)) we get if(!rpmsg_lite_dev != NULL) which is something different. I only caught this, because I got compiler warnings like this:

In file included from /project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/include/rpmsg_env.h:83:0,                                          
                 from /project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/include/virtqueue.h:36,                                            
                 from /project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/include/rpmsg_lite.h:41,                                           
                 from /project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/rpmsg_lite/rpmsg_lite.c:33:                                        
/project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/rpmsg_lite/rpmsg_lite.c: In function 'rpmsg_lite_rx_callback':                           
/project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/rpmsg_lite/rpmsg_lite.c:160:30: warning: comparison between pointer and integer          
     RL_ASSERT(rpmsg_lite_dev != NULL);                                
                              ^
/project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/include/rpmsg_default_config.h:76:14: note: in definition of macro 'RL_ASSERT'           
         if (!x)       \                                               
              ^
/project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/rpmsg_lite/rpmsg_lite.c: In function 'rpmsg_lite_tx_callback':                           
/project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/rpmsg_lite/rpmsg_lite.c:201:30: warning: comparison between pointer and integer          
     RL_ASSERT(rpmsg_lite_dev != NULL);                                
                              ^
/project/rpu_firmware/libs/rpmsg_lite/rpmsg-lite/lib/include/rpmsg_default_config.h:76:14: note: in definition of macro 'RL_ASSERT'           
         if (!x)       \ 

An easy fix is to just wrap the x in if(!x) with a pair of parentheses like this: if(!(x)).

rpmsg_lite_send timeout not honored (virtqueue_kick may get stuck)

Hello, I'm running RPMsg lite in two Cortex-M4 (MX8QM, FreeRTOS 10).
The normal use cases are OK, however I'm working on edge situations.

For instance, if a node transmits a message with rpmsg_lite_send(...., timeout=100ms) and the other node is stuck (e.g., is in assert(false) or paused by JTAG), then the rpmsg_lite_send() will not return an error after 100ms.
This happens because virtqueue_kick() is called without a reference to the timeout, and in my case MU_SendMsg() gets called, which gets stuck in an infinite while loop waiting for some flag that will never change (since the other M4 is dead).

I have work-arounded this issue by monkey-patching the code in an horrible way. It gets the job done, but I deserve the programmer's hell (done of tiny .svn directories everywhere for the eternity); however I would like to know what you think about this and if you are interested in a more elegant solution.

Thank you!
Francesco

Communicating with QNX

Hello

I am working on a project using one of the i.MX8 variants. The code running on the Cortex-M is bare metal and I have integrated rpmsg-lite into the firmware using the appropriate environment and platform files.

The Cortex-A cluster is running QNX, is there an existing library that I can include into the QNX application to be able to communicate with the Cortex-M4 or will this require a generic POSIX compliant platform to be developed for rpmsg-lite?

-Andy.

How to use the rpmsg-lite

rpmsg-lite is a very great open source software, but are there any examples of how to use it and look forward to them.

Can I run rpmsg-lite with Yocto Hardkott Or Kirkstone Or Only with NXP downstream kernel?

Hi,

This is the main project file:

https://gist.github.com/neuberfran/c3fc054a4640e809231ddc587947819a

As you can see in the photos linked below, it hangs on the following line:
rpmsg_lite_is_link_up

https://drive.google.com/drive/folders/1loIpXypW1lMcBy9CxSiIJeIbN0uWtkkL?usp=drive_link

Regarding the photos above, special attention should be paid to the result of the dmesg | grep -E "MU|rpmsg"

In one of the photos (in which I used warp7-m4 and zephyr 1.13 the compilation worked and the results for the above command were better

I'm sure my device tree is correct:

Can I run rpmsg-lite with Yocto Hardkott Or Kirkstone Or Only with NXP downstream kernel?

Is it possible one core used as server and client at same time?

I have two cores(call them A and B), using rpmsg-lite to communicate between them, core A
has some peripheral(like UART) and core B mainly as DSP.
When playing audio, IMO, core A used as client, and core B severed as server, but when printing
trace, the role is changed, A as Server and B as client? So the A(or B) used as server
and client at same time, is it possible? please give some advice.
Thanks a lot.

[QUESTION]: Erpc and rpmsg port to embOS

hi,
On a NXP MCU, We are using the the rpmsg_lite layer and the shared memory for the communication.
We are using the RTOS embOS of SEGGER.

Do you have the files of environnent to run this example with embOS?

Files for the porting are : rpmsg_lite/porting/environment/rpmsg_env_freertos.c and environment/freertos/rpmsg_env_specific.h

That would be great to speed up the project development.

thank you
Guillaume

Invalid and Duplicate vring desc indices from avail

There appears to be a built in assumption when creating the virtuequeue structure that the first index to be read from the vring should be 0. vq->available_idx get's zero initialized which causes it to look at avail->ring[0] for the first read. This assumption breaks down if any rpmsg transactions have occurred previously.

The issue I ran into is as follows:

  1. load a dummy m4 rpmsg application with uboot. (pingpong_bm.bin)
  2. boot Linux and load the rpmsg_char driver
  3. use m4fwloader to load the desired m4 application that uses rpmsg
  4. grab 3 tx rpmsg buffer pointers and fill with data
  5. run until there is a duplicate buffer returned from rpmsg_lite_alloc_tx_buffer()

In the example above the pingpong_bm application on the m4 sends one message to the A7 when it comes online and waits for the driver to send it a value. The A7 has already filled the tvq->avail ring with 256 messages so the idx value stored in the M4 TX avail ring is 256. When the pingpong_bm sends a message it causes the A7 to processes the buffer and put it back in the avail ring as expected at the 0 index and advances the avail->idx to 257. This is okay so far and correct behavior.

The issue occurs when another rpmsg application is loaded onto the m4 and starts getting tx buffers. Because the vq->available_idx is zero initialized the new application looks in avail->ring[0] instead of avail->ring[1]. The system should be looking at 1 because 1 message has already been sent and processed so the "read pointer" for the avail ring has been advanced. This information is lost when the new program is loaded. When the new program sends the message the A7 side processes it and puts the idx back into the avail ring. The avail->ring now has duplicate desc indices. I.E.

avail->ring[0] = 0
avail->ring[1] = 0

Now when the m4 application grabs the next tx buffer it gets desc index 0 again and begins to fill that with data. This can cause a number of problems. The M4 can modify data while the A7 is attempting to read and process the buffer. If the M4 requested multiple tx buffers it could be clobbering data unknowingly as it has two pointers to the same location. This issue also fails silently, causing data corruption and race condition issues.

This issue may be larger than just rpmsg-lite, it might be a flaw in the virtio design itself. It seems like there is no shared memory location that tracks the location of the consumer/reader pointer, there is only idx which tracks the producer/writer pointer.

Proposed Solutions:
Either

  1. Add documentation that states the m4 application using rpmsg-lite must be the first application loaded and cannot be reloaded after a message has been sent.
    OR
  2. Modify the initialization of the available_idx value in the virtqueue structure so that it doesn't always start at 0 and somehow accounts for current idx value stored in the avail ring.
    OR
  3. Update the vring structures so that they store the reader idx as well as the writer idx.

openamp compatibility?

Is this fully implementation fully compliant with openamp as well as rpmsg in the kernel? Can you provide snippet for openamp and rpmsg-lite setup to test interop?

Update RL_BUFFER_COUNT Documentation

After some testing I found that the RL_BUFFER_COUNT configuration parameter must be half of the total number of RPMsg buffers when interfacing with Linux RPMsg. The documentation says that it's the total number of buffers but the source code treats it as the number of buffers in one direction, so it's actually half of the total number of buffers.

Setting RL_BUFFER_COUNT to the total number of allocated buffers causes the memory map of the vrings to be incorrect.

EX: if Linux RPMSG_NUM_BUFS = 512 then RL_BUFFER_COUNT must equal 256.

[QUESTION] virtio VIRTIO_F_EVENT_IDX

Does rpmsg-lite support VIRTIO_F_EVENT_IDX ? In my use case the remote side will set a value to reduce notify interrupt genereted by host.
If it does, where can I find an example to use it?

RPMsg-Lite Bare Metal Example

Hello,

Is there a working example of running RPMsg-Lite on bare metal (my target is i.MX8MM but the example doesn't need to be)?

The FreeRTOS example uses a queue, which bare metal doesn't have, and uses a blocking rpmsg_queue_recv() function.

If I try to use the FreeRTOS example as-is in my bare metal code then the linker complains about missing env_put_queue() and env_create_queue() functions. The bare metal Cortex-M4 firmware is the "remote" side.

Thanks in advance.

-Andy

configSUPPORT_STATIC_ALLOCATION vs RL_USE_STATIC_API => RL_USE_STATIC_API is not entirely static

Hi @MichalPrincNXP ,
i wanted to inform you that i am working on STATIC memory usage in RPMSG. This macro RL_USE_STATIC_API isn't from may point of view best approach. In description:

//! @def RL_USE_STATIC_API
//!
//! Static API functions (no dynamic allocation) enabled/disabled.
//! The default value is 0 (static API disabled).
#define RL_USE_STATIC_API (1)

But RPMSG for FREERTOS is using dynamic memory allocations. So it is not entirely static api.

I am preparing PR where Freertos static functions can be called instead of dynamic when
#define configSUPPORT_STATIC_ALLOCATION 1.

But i wanted let you think about this case until that. Because then user will need set two macros to get entirely static api usage and that doesn't sounds good to me.

EDIT: Maybe i can check if configSUPPORT_STATIC_ALLOCATION == RL_USE_STATIC_API and force user to set both macros.

Can rpmsg lite work well as master and remote at the same time?

On my board, there are three cores. 1 APU and 2 R52s. Then APU works as a master to communicate with R52 A, also R52 A should actively send some message to R52 B. So for R52 A, it should run both rpmsg_lite_master_init and rpmsg_lite_remote_init. I want to know if the rpmsg-lite code can support the use like this? someone's share may help me a lot , tks.

Sequencing, master or remote to invoke init first?

In the rpmsg protocol, who should invoke init first? Shall the remote invoke rpmsg_lite_remote_init first and then the master invokes rpmsg_lite_master_init? Or is it the other way around?

Another question, how is this link_state supposed to work? Looks like the master puts link_state to 1 whereas slave puts it to 0. Can this be reliable used somehow to know when both sides are ready?

[QUESTION]: Remote and master on the same core?

Hello.

i.MX8M plus

If I fix the code would it (for testing purposes) be possible to run both master (on MU1A) and remote (on MU1B) on the same M7 core or are there hardware constraints that prevent this?

Message framentation?

Does rpmsg-lite have any plans to support message fragmentation? Currently the rpmsg_lite_send simply drops the message if the size exceeds RL_BUFFER_PAYLOAD_SIZE

who will set rpmsg_lite_dev->link_state to 1

In boards/evkmimx8mq/multicore_examples/rpmsg_lite_pingpong_rtos/linux_remote/main_remote.c file,
In my view, after call rpmsg_lite_remote_init, the local direct to wait link_up will have something not good, who will set rpmsg_lite_dev->link_state to 1 let the task run continue, if no one set rpmsg_lite_dev->link_state to 1, the task will block here.
`
static void app_task(void *param)
{
volatile uint32_t remote_addr;
volatile rpmsg_ns_handle ns_handle;

/* Print the initial banner */
(void)PRINTF("\r\nRPMSG Ping-Pong FreeRTOS RTOS API Demo...\r\n");

#ifdef MCMGR_USED
uint32_t startupData;
mcmgr_status_t status;

/* Get the startup data */
do  
{   
    status = MCMGR_GetStartupData(&startupData);
} while (status != kStatus_MCMGR_Success);

my_rpmsg = rpmsg_lite_remote_init((void *)(char *)startupData, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);

/* Signal the other core we are ready by triggering the event and passing the APP_RPMSG_READY_EVENT_DATA */
(void)MCMGR_TriggerEvent(kMCMGR_RemoteApplicationEvent, APP_RPMSG_READY_EVENT_DATA);

#else
(void)PRINTF("RPMSG Share Base Addr is 0x%x\r\n", RPMSG_LITE_SHMEM_BASE);
my_rpmsg = rpmsg_lite_remote_init((void )RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
#endif /
MCMGR_USED */
rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK);
(void)PRINTF("Link is up!\r\n");
`

use env_rmb() is for what?

I have a question about the use of env_rmb() function in rpmsg_lite/virtio/virtqueue.c virtqueue_get_buffer. It seems that both used_idx and uep are dependent on the following code, so doesn't the program itself reorder? env_rmb() is used here to prevent reordering of which code?

[QUESTION] Environment porting unit-tests

Hello all,

The documentation states that some environment porting is tested but I could not find any unit tests in the code base.
Are these unit tests available anywhere else? Would you be able to share it with the community?

Thanks

Request for help to setup multiple endpoints on 1 RPSMG channel

Hi

I'm trying to set up the rpmsg communication between the A7 and M4 of IMX7D. I found a rpmsg-lite example at https://github.com/EmbeddedRPC/erpc-imx-demos, was able to make it run and send some data from A7 to the M4.

The example creates only 1 channel and 1 endpoint on the M4 side. I need 2 endpoint on the same channel.

I tinkered with the example in the hope to set up a second endpoint on the same channel. But my change only lead to the creation of a second channel on the A7 side.

my attempt to create a second endpoint:
`

    my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RL_PLATFORM_IMX7D_M4_LINK_ID, RL_NO_FLAGS);
my_queue = rpmsg_queue_create(my_rpmsg);
my_autobus1_queue = rpmsg_queue_create(my_rpmsg);

PRINTF("Waiting for master to get ready...\r\n");

while(!rpmsg_lite_is_link_up(my_rpmsg))
{
	PRINTF(".");
    v00TaskDelay(300);
}
/*	Create the system endpoint								                                             */
PRINTF("\r\n create system  endpoint\r\n");
system_ept = rpmsg_lite_create_ept(my_rpmsg, SYSTEM_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_queue);
PRINTF("Sending name service announcement to Linux...\r\n");
    rpmsg_ns_announce(my_rpmsg, system_ept, "rpmsg-openamp-demo-channel", RL_NS_CREATE);


/*	Create the AUTOBUS 1 endpoint												       */
PRINTF("create autobus_1 endpoint\r\n");
autobus1_ept = rpmsg_lite_create_ept(my_rpmsg, AUTOBUS1_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb,my_autobus1_queue);

PRINTF("Sending name service announcement to Linux...\r\n");
rpmsg_ns_announce(my_rpmsg, autobus1_ept, "rpmsg-openamp-demo-channel", RL_NS_CREATE)

PRINTF("Waiting for any messages from Linux...\r\n");

while(true);

`
A snippet of the A7 debug console:

NXP i.MX Release Distro 4.14-sumo pico-imx7 ttymxc4
pico-imx7 login: root
root@pico-imx7:~# cd /
root@pico-imx7:/# modprobe rpmsg_multiept
rpmsg: new channel 0x400 -> 0x1e
rpmsg: new channel 0x401 -> 0x1f

Are there any examples or info available on how to setup multiple rpmsg endpoint on 1 channel on the M4 side?

Kind regards
Diek

Issue with registering of interrupts

(https://github.com/NXPmicro/rpmsg-lite/blob/bb3e24d7c67a33d83f976a574effa205d19ac368/lib/rpmsg_lite/rpmsg_lite.c#L1134)

The 'platform_init_interrupt' function is called twice in 'rpmsg_lite_master_init' and twice here in 'rpmsg_lite_remote_init'.

It seems that the second write will overwrite the 'isr_table' structure.

The first two calls in 'rpmsg_lite_master_init' will pass the indices as 0 and 1.
And the next two calls 'rpmsg_lite_remote_init' will pass the indices as 1 and 0, effectively overwriting the values set in the first calls.

I'm not sure if this is an issue with the code here or it should be handled somehow in the 'environment' or 'platform'. (Note: I discovered this issue while using the rpmsg_env_bm.c.)

Program hangs in rpmsg_lite_release_rx_buffer()

First of all thank you for this useful library.
Note that in rpmsg_lite_release_rx_buffer() function there is a RL_ASSERT macro to expect a buffer pointer value inside a range, but...From the master side in Linux, these buffers are allocated using dma_alloc_coherent so a virtual address is expected which does not match what the RL_ASSERT macro expects, therefore my program hangs there.
I'm using a iMX7D with these configuration for the rpmsg:
DT:
&rpmsg{
vdev-nums = <1>;
reg = <0xbfff0000 0x80000>;
status = "okay";
};
RPMSG-LITE
#define BOARD_SHARED_MEMORY_BASE (void *)0xBFFF0000
#define RL_BUFFER_COUNT (256)
#define RL_BUFFER_PAYLOAD_SIZE (496)

With these parameters, when i receive something from the master side, the rx buffer addr is at 0xAA... and RL_ASSERT triggers.
Any ideas? Thanks in advance

Address translation is required if the shared memory space is differently mapped by the two cores

Hello,

I got a hardfault while implementing a ping-pong example between a CM33 (configured as the rpsmg-lite master) and a CM0+ (configured as the rpmsg-lite remote) core in a multicore chip. The hardfault happened on the CM0+, because the shared space memory is differently mapped by the two cores. The shared memory space starts from SH_MEM_MASTER_BASE_ADDRESS for the CM33 side and from SH_MEM_REMOTE_BASE_ADDRESS for the CM0+ side.

I added the following workaround to rpmsg-lite.c, implementing the shared memory address translation from master to remote addresses:

.........
    /* Process the received data from remote node */
    rpmsg_msg = (struct rpmsg_std_msg *)rpmsg_lite_dev->vq_ops->vq_rx(rpmsg_lite_dev->rvq, &len, &idx);

#if (REMOTE_PROCESSOR)
    if (rpmsg_msg != RL_NULL)
    {
        rpmsg_msg = (struct rpmsg_std_msg *) (SH_MEM_REMOTE_BASE_ADRRESS + (uint32_t) rpmsg_msg - SH_MEM_MASTER_BASE_ADDRESS);
    }
#endif

    while (rpmsg_msg != RL_NULL)
    {
        node = rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, rpmsg_msg->hdr.dst);
.........

#if (REMOTE_PROCESSOR)
    if (rpmsg_msg != RL_NULL)
    {
        rpmsg_msg = (struct rpmsg_std_msg *) (SH_MEM_REMOTE_BASE_ADRRESS + (uint32_t) rpmsg_msg - SH_MEM_MASTER_BASE_ADDRESS);
    }
#endif
    }

#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
    env_unlock_mutex(rpmsg_lite_dev->lock);
#endif
}

and

.....
    /* Get rpmsg buffer for sending message. */
    buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx);
#if (REMOTE_PROCESSOR)
    if (buffer != RL_NULL)
    {
        rpmsg_msg = (struct rpmsg_std_msg *) (SH_MEM_REMOTE_BASE_ADRRESS + (uint32_t) rpmsg_msg - SH_MEM_MASTER_BASE_ADDRESS);
    }
#endif
 .....
    while (buffer == RL_NULL)
    {
        env_sleep_msec(RL_MS_PER_INTERVAL);
        env_lock_mutex(rpmsg_lite_dev->lock);
        buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx);
#if (REMOTE_PROCESSOR)
        if (buffer != RL_NULL)
        {
            rpmsg_msg = (struct rpmsg_std_msg *) (SH_MEM_REMOTE_BASE_ADRRESS + (uint32_t) rpmsg_msg - SH_MEM_MASTER_BASE_ADDRESS);
        }
#endif
.......

Best Regards,
Kostas

RPMSG buffer size and buffer count

Hi @MichalPrincNXP,

I was trying to increase the RPMSG buffer size and buffer count both on A7 and M4 side. Our goal is to use (16 * 16KB) buffers. Below are test results with different configurations performed on 5.4 linux-imx based kernel:

Buffer size Buffer count Boot result
512 512
1024 256
2048 128
4096 64
8192 32
16384 16
32768 8
  • ✅ means that the board boots normally and you get the /dev/ttyRPMSG* char device
  • ❌ means that there is a kernel panic during boot related with pf1550-regulator-rpmsg.c kernel driver

If I disable CONFIG_REGULATOR_PF1550_RPMSG driver, Linux boots normally, the /dev/ttyRPMSG* char device is created and everything works as expected.

Parts of our device tree that might be relevant:

...
	pf1550-rpmsg {
		compatible = "rohm,bd70528-rpmsg";
		sw1_reg: SW1 {
				regulator-name = "SW1";
				regulator-min-microvolt = <1200000>;
				regulator-max-microvolt = <3400000>;
				regulator-boot-on;
				regulator-always-on;
		};

		sw2_reg: SW2 {
				regulator-name = "SW2";
				regulator-min-microvolt = <1200000>;
				regulator-max-microvolt = <3300000>;
				regulator-boot-on;
				regulator-always-on;
		};

		sw3_reg: SW3 {
				regulator-name = "SW3";
				regulator-min-microvolt = <1200000>;
				regulator-max-microvolt = <1200000>;
				regulator-boot-on;
				regulator-always-on;
		};

		vldo1_reg: LDO1 {
				regulator-name = "LDO1";
				regulator-min-microvolt = <1650000>;
				regulator-max-microvolt = <3300000>;
				regulator-boot-on;
				regulator-always-on;
		};

		vldo2_reg: LDO2 {
				regulator-name = "LDO2";
				regulator-min-microvolt = <1650000>;
				regulator-max-microvolt = <3300000>;
				regulator-boot-on;
				regulator-always-on;
		};

		vldo3_reg: LDO3 {
				regulator-name = "LDO3";
				regulator-min-microvolt = <1650000>;
				regulator-max-microvolt = <3300000>;
				regulator-always-on;
		};
	};

	imx7ulp-cm4 {
		compatible = "fsl,imx7ulp-cm4";
		ipc-only;
		rsc-da=<0x1fff8000>;
		mbox-names = "tx", "rx", "rxdb";
		mboxes = <&mu 0 1
			  &mu 1 1
			  &mu 3 1>;
		memory-region = <&vdev0vring0>, <&vdev0vring1>,
				<&vdev1vring0>, <&vdev1vring1>;
	};
...
&rpmsg{
	/*
	 * 64K for one rpmsg instance, default using 2 rpmsg instances:
	 * --0x9DF00000~0x9DF0FFFF: pmic,pm,audio,keys,gpio,sensor
	 * --0x9DF10000~0x9DF1FFFF: pingpong,virtual tty
	 */
	vdev-nums = <2>;
	reg = <0x9DF00000 0x20000>;
	status = "okay";
};

Below are diffs used in tests (showing (16 * 16KB) buffers in this case). Linux side:

diff --git a/drivers/rpmsg/imx_rpmsg.c b/drivers/rpmsg/imx_rpmsg.c
index 9dd704ae5a64..5d3617e02a49 100644
--- a/drivers/rpmsg/imx_rpmsg.c
+++ b/drivers/rpmsg/imx_rpmsg.c
@@ -69,8 +69,8 @@ struct imx_rpmsg_vproc {
  */
 #define REMOTE_READY_WAIT_MAX_RETRIES  500
 
-#define RPMSG_NUM_BUFS         (512)
-#define RPMSG_BUF_SIZE         (512)
+#define RPMSG_NUM_BUFS         (16)
+#define RPMSG_BUF_SIZE         (16384)
 #define RPMSG_BUFS_SPACE       (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
 #define RPMSG_VRING_ALIGN      (4096)
 #define RPMSG_RING_SIZE        ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \

M4 side:

diff --git a/Firmware/pilot/source/rpmsg_config.h b/Firmware/pilot/source/rpmsg_config.h
index 7b15fa84..c51affef 100755
--- a/Firmware/pilot/source/rpmsg_config.h
+++ b/Firmware/pilot/source/rpmsg_config.h
@@ -31,13 +31,13 @@
 //! Size of the buffer payload, it must be equal to (240, 496, 1008, ...)
 //! [2^n - 16].
 //! The default value is 496U.
-#define RL_BUFFER_PAYLOAD_SIZE (496U)
+#define RL_BUFFER_PAYLOAD_SIZE (16368U)
 
 //! @def RL_BUFFER_COUNT
 //!
 //! Number of the buffers, it must be power of two (2, 4, ...).
 //! The default value is 2U.
-#define RL_BUFFER_COUNT (256U)
+#define RL_BUFFER_COUNT (8U)
 
 //! @def RL_API_HAS_ZEROCOPY
 //!

who will set rpmsg_lite_dev->link_state to 1

In boards/evkmimx8mq/multicore_examples/rpmsg_lite_pingpong_rtos/linux_remote/main_remote.c file,
In my view, after call rpmsg_lite_remote_init, the local direct to wait link_up will have something not good, who will set rpmsg_lite_dev->link_state to 1 let the task run continue, if no one set rpmsg_lite_dev->link_state to 1, the task will block here.
`
static void app_task(void *param)
{
volatile uint32_t remote_addr;
volatile rpmsg_ns_handle ns_handle;

/* Print the initial banner */
(void)PRINTF("\r\nRPMSG Ping-Pong FreeRTOS RTOS API Demo...\r\n");

#ifdef MCMGR_USED
uint32_t startupData;
mcmgr_status_t status;

/* Get the startup data */
do  
{   
    status = MCMGR_GetStartupData(&startupData);
} while (status != kStatus_MCMGR_Success);

my_rpmsg = rpmsg_lite_remote_init((void *)(char *)startupData, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);

/* Signal the other core we are ready by triggering the event and passing the APP_RPMSG_READY_EVENT_DATA */
(void)MCMGR_TriggerEvent(kMCMGR_RemoteApplicationEvent, APP_RPMSG_READY_EVENT_DATA);

#else
(void)PRINTF("RPMSG Share Base Addr is 0x%x\r\n", RPMSG_LITE_SHMEM_BASE);
my_rpmsg = rpmsg_lite_remote_init((void )RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
#endif /
MCMGR_USED */
rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK);
(void)PRINTF("Link is up!\r\n");
`

[QUESTION] Does rpmsg_lite_send require carriage returns?

In using rpmsg_lite_send(), I noticed that if I did not include a carriage return ("/r/n") at the end of my Tx data that it would not work. Does this sound accurate with the implementation? If so why must it require a carriage return?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.