Bare metal RPMSG on Verdin

Hi, I am trying to run the RPMSG-Lite on bare metal M4. The two rpmsg examples in the MCUXpresso SDK are built with freeRTOS. Extracting the code is not the problem, but the build process is, because all the cmake settings and includes are set for FreeRTOS and not bare-metal.
Only example I could find using bare metal was this one, but it uses a different (older) template of cmake files and older rpmsg version, so it is hard to translate. From the RPMsg-Lite Users’s Guide it is explained that rpmsg_env_bm.c should be used instead of rpmsg_env_freertos.c. But the things are a bit complicated that that. Going from the boards\evkmimx8mm\multicore_examples\rpmsg_lite_str_echo_rtos example, the rpmsg folder under middleware\multicore, has a few cmake files to be included as modules inside CMakeLists.txt:
middleware_multicore_rpmsg_lite_imx8mm_m4_freertos_MIMX8MM6
middleware_multicore_rpmsg_lite_freertos_MIMX8MM6
middleware_multicore_rpmsg_lite_MIMX8MM6
The last few lines of the last cmake file:

if(CONFIG_USE_middleware_multicore_rpmsg_lite_freertos_MIMX8MM6)
     include(middleware_multicore_rpmsg_lite_freertos_MIMX8MM6)
endif()
if(CONFIG_USE_middleware_multicore_rpmsg_lite_bm_MIMX8MM6)
     include(middleware_multicore_rpmsg_lite_bm_MIMX8MM6)
endif()
if(NOT (CONFIG_USE_middleware_multicore_rpmsg_lite_freertos_MIMX8MM6 OR CONFIG_USE_middleware_multicore_rpmsg_lite_bm_MIMX8MM6))
    message(WARNING "Since middleware_multicore_rpmsg_lite_freertos_MIMX8MM6/middleware_multicore_rpmsg_lite_bm_MIMX8MM6 is not included at first or config in config.cmake file, use middleware_multicore_rpmsg_lite_bm_MIMX8MM6 by default.")
    include(middleware_multicore_rpmsg_lite_bm_MIMX8MM6)
endif()

Imply that there should also be an middleware_multicore_rpmsg_lite_bm_MIMX8MM6 file. It does not exist though. I tried creating one analogous to the freertos file (also changing the config.cmake accordingly), but I am still stuck at an build error:

c:/progra~2/gnuarm~1/102021~1.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: CMakeFiles/main.elf.dir/C_/workspace/Verdin/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c.obj: in function `rpmsg_queue_rx_cb':
C:\workspace\Verdin\multicore\rpmsg_lite\lib\rpmsg_lite/rpmsg_queue.c:47: undefined reference to `env_put_queue'
c:/progra~2/gnuarm~1/102021~1.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: CMakeFiles/main.elf.dir/C_/workspace/Verdin/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c.obj: in function `rpmsg_queue_create':
C:\workspace\Verdin\multicore\rpmsg_lite\lib\rpmsg_lite/rpmsg_queue.c:77: undefined reference to `env_create_queue'
c:/progra~2/gnuarm~1/102021~1.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: CMakeFiles/main.elf.dir/C_/workspace/Verdin/multicore/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c.obj: in function `rpmsg_queue_recv_nocopy':
C:\workspace\Verdin\multicore\rpmsg_lite\lib\rpmsg_lite/rpmsg_queue.c:179: undefined reference to `env_get_queue'

Those are all function that are contained inside of rpmsg_env.h file, that should be included. To make it less complicated, the 3 modified cmake module files I’m adding to my CmakeLists file would look like this:

###middleware_multicore_rpmsg_lite_imx8mm_m4_bm_MIMX8MM6####
include_guard()
message("middleware_multicore_bm_lite_bm component is included.")


target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_bm.c
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c
)


target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/include/environment/bm
)



######middleware_multicore_rpmsg_lite_MIMX8MM6######

include_guard()
message("middleware_multicore_rpmsg_lite component is included.")

target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/common/llist.c
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/rpmsg_lite/rpmsg_lite.c
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/rpmsg_lite/rpmsg_ns.c
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/virtio/virtqueue.c
)


target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/include
)


#OR Logic component
if(CONFIG_USE_middleware_multicore_rpmsg_lite_freertos_MIMX8MM6)
     include(middleware_multicore_rpmsg_lite_freertos_MIMX8MM6)
endif()
if(CONFIG_USE_middleware_multicore_rpmsg_lite_bm_MIMX8MM6)
     include(middleware_multicore_rpmsg_lite_bm_MIMX8MM6)
endif()
if(NOT (CONFIG_USE_middleware_multicore_rpmsg_lite_freertos_MIMX8MM6 OR CONFIG_USE_middleware_multicore_rpmsg_lite_bm_MIMX8MM6))
    message(WARNING "Since middleware_multicore_rpmsg_lite_freertos_MIMX8MM6/middleware_multicore_rpmsg_lite_bm_MIMX8MM6 is not included at first or config in config.cmake file, use middleware_multicore_rpmsg_lite_bm_MIMX8MM6 by default.")
    include(middleware_multicore_rpmsg_lite_bm_MIMX8MM6)
endif()



######middleware_multicore_rpmsg_lite_bm_MIMX8MM6###############


include_guard()
message("middleware_multicore_bm_lite_bm component is included.")


target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_bm.c
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/rpmsg_lite/rpmsg_queue.c
)


target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/rpmsg_lite/lib/include/environment/bm
)


If you take a look at the example code, this is almost the same as the freertos system apart from two module imports:

include(middleware_freertos-kernel_MIMX8MM6)

include(middleware_freertos-kernel_heap_4_MIMX8MM6)

I guess I shouldn’t import them since I’m not using freertos.

There is a lot of additional info, please ask for details if something is left unclear.

Thanks in advance!

Upon further search, I realized that rpmsg_env_bm.c does not contain the mentioned “env_put_queue, env_get_queue and env_get_queue” functions, they are only contained inside rpmsg_env.h and rpmsg_env_freertos.c files. Does this mean when using the bare metal the whole rpmsg_queue.c file is unusable and custom functions have to be written?

EDIT: One person mentioned here that “queues depend on rtos” so I guess I’m on the right track, but I still can’t find any solution. I can’t understand that the official documentation nonchalantly mentions the bare metal environment file that is obviously not fully implemented…

Hi @swiss,

I’m still taking a look into this. Here I got the example of the FreeRTOS RPMSG and remove all the RTOS-related stuff (like includes and tasks functions) and it worked. However, I compiled it using the CMake from the RTOS demo, not the bare metal one. Here is where things are different.

Meanwhile, have you seen this file?

middleware/multicore/rpmsg_lite/lib/rpmsg_lite/porting/environment/rpmsg_env_bm.c

These are the rpmsg-lite bare metal functions… do you think it could help you in something?

I feel that RPMSG-lite should work regardless of FreeRTOS. Looking at the NXP documentation, here is what I can see:

If this diagram is correct, there is nothing related to an RTOS, this library should work “alone”. I’ll have to dig into this a little further to find where the functions are being called.

I would suggest you ask this in the NXP community aswell, maybe they could point you in the right direction.

Best Regards,
Hiago.

Hi @hfranco.tx ,

The graph does show it as ready-to-go, but only a few sentences under in the same NXP Documentation it says:

Queue sub-component (optional)

This subcomponent is optional and requires implementation of the env_*_queue() functions in the environment porting layer.

So I guess my question is closed. The way they formulated the User’s Guide lost me around 6 hours of work, but yeah…
If someone has the full bare-metal implementation for Verdin that they can share, that would be nice, I don’t wanna lose my time on that. I will try using the FreeRTOS instead.

1 Like

Hi @swiss,

I’ll share with you if we manage to use the RPMsg with bare metal code. For now, I tested only using FreeRTOS.

Best Regards,
Hiago.

Hello @hfranco.tx ,

Sorry for commenting on an old thread, but did you manage to run RPMsg without RTOS ?

Best,
Ahmed

Hi @AhmedMobarez,

I haven’t tried it myself, however, if you check the RTOS code, it’s only creating a task that will run the RPMSG inside that task. S you can check the code inside the task to see how it works.

void app_task(void *param)
{
    volatile uint32_t remote_addr;
    void *rx_buf;
    uint32_t len;
    int32_t result;
    void *tx_buf;
    uint32_t size;

    /* Print the initial banner */
    PRINTF("\r\nRPMSG String Echo FreeRTOS RTOS API Demo...\r\n");

#ifdef MCMGR_USED
    uint32_t startupData;

    /* Get the startup data */
    (void)MCMGR_GetStartupData(kMCMGR_Core1, &startupData);

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

    /* Signal the other core we are ready */
    (void)MCMGR_SignalReady(kMCMGR_Core1);
#else
    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);

    my_queue = rpmsg_queue_create(my_rpmsg);
    my_ept   = rpmsg_lite_create_ept(my_rpmsg, LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_queue);
    (void)rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, RL_NS_CREATE);

    PRINTF("\r\nNameservice sent, ready for incoming messages...\r\n");

    for (;;)
    {
        /* Get RPMsg rx buffer with message */
        result =
            rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, (uint32_t *)&remote_addr, (char **)&rx_buf, &len, RL_BLOCK);
        if (result != 0)
        {
            assert(false);
        }

        /* Copy string from RPMsg rx buffer */
        assert(len < sizeof(app_buf));
        memcpy(app_buf, rx_buf, len);
        app_buf[len] = 0; /* End string by '\0' */

        if ((len == 2) && (app_buf[0] == 0xd) && (app_buf[1] == 0xa))
            PRINTF("Get New Line From Master Side\r\n");
        else
            PRINTF("Get Message From Master Side : \"%s\" [len : %d]\r\n", app_buf, len);

        /* Get tx buffer from RPMsg */
        tx_buf = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &size, RL_BLOCK);
        assert(tx_buf);
        /* Copy string to RPMsg tx buffer */
        memcpy(tx_buf, app_buf, len);
        /* Echo back received message with nocopy send */
        result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, remote_addr, tx_buf, len);
        if (result != 0)
        {
            assert(false);
        }
        /* Release held RPMsg rx buffer */
        result = rpmsg_queue_nocopy_free(my_rpmsg, rx_buf);
        if (result != 0)
        {
            assert(false);
        }
    }
}

You can check on the main_remote.c file from the NXP demo.

Best Regards,
Hiago.