CPUAPP-CPUNET Firmware

Hello, Nordicsemi community,

I am a bit confused about how I need to proceed in order to use both cores in my nRF5340 that lives in a custom board.

I was playing with the DK to do some Enhanced Shock-Burst testing and after following the instruction of the sample for the correct building, I am sorry to see that I can't get any logged info in my console (I tried both COM port). If I flash the "Hello World" sample on the same board, I can see the print correctly in the console, even if I flash the cpunet application afterward.

So, what do I need to do to see the prints coming from the cpunet application?

Also, is this (creating and building two separate applications) the correct way to use both cores? Also how do I share data between the cores? E.g: collecting data via ESB in the net core and then elaborating them in the application core.

Finally, for my custom board, how do I work with both cores?

Thanks!

Parents
  • There are multiple ways to build the application for both cores.

    It partly depends on whether you build the Secure or Non-Secure variant, and it depends on whether you build separate images or (the default) multi image build.

    Nordic examples include a prebuilt app for CPUNET called hci_rpmsg which implements a Bluetooth controller communicating via OpenAMP RPMSG protocol.

    The kernel option to disable it in CPUAPP is: CONFIG_NCS_INCLUDE_RPMSG_CHILD_IMAGE=n
    If you put that in prj.conf (or otherwise specified kernel config file) the default child image will not be built and included.

    The default hci_rpmsg can be configured by creating child_image/hci_rpmsg.conf file with Zephyr kernel configuration options. You probably want CONFIG_LOG=y - the defaults will output to the second UART. Configure it like you would logging for CPUAPP.
    You can also use RTT output for that core, but attaching there does not work properly with Non-Secure mode applications and will interfere with the execution.
    If you build a Non-Secure variant, one of the UARTs is taken by default for logging from TF-M loader. There are kernel options to disable it.

    You can include a custom CPUNET image with some CMake trickery including a zephyr module, see nrf/samples/nrf5340/multicore.
    The trickery is required to prevent an infinite include loop.

    hci_rpms uses Zephyr IPC services with OpenAMP RPMsg backend to implement the communication between the cores, a pretty powerful toolkit which is too much to describe in the simple post.

    The details of the backend are configured using the Device Tree, which you can find in the various nrf5340 related device tree dtsi files in Zephyr.
    These use nordic,mbox-nrf-ipc for the low level MBOX module configuration and zephyr,ipc-openamp-static-vrings.for the higher level OpenAMP RPMSG configuration which specifies that Mbox.
    IPC module is described here: https://infocenter.nordicsemi.com/topic/ps_nrf5340/ipc.html
    But unless you want to do it low level, use Zephyr IPC services instead: docs.zephyrproject.org/.../ipc_service.html

    Generally since it is CPU-specific rather than board specific you should not need to change them, unless you want to use some sort of external memory for the IPC or need to make the buffers big, whihc would require changing the sram0_shared definition.

    Another example using OpenAMP RPMSG would be in nrf/applications/nrf5340_audio - more complicated, different design.

  • I was exploring the IPC Service example here developer.nordicsemi.com/.../README.html

    And it says that "both application and network cores periodically print out the receiving speed of data that was sent by the other core".

    Although I think I have understood the configuration of the example, it's not quite clear to me how it is able to print the speed of data.

    In the code https://github.com/nrfconnect/sdk-nrf/blob/main/samples/ipc/ipc_service/src/main.c (that is executed from both cpuapp and cpunet in the default build configuration), I just find a thread defined that run the "check_task", but it prints info from the p_payload global variable. I don't get where this p_payload is populated with information that comes from the other core.

  • I am quite confident to say that the example doesn't do what it is supposed to do. It doesn't print the throughput of data coming from the other core, because the callback for the received data is never used correctly. It just prints the throughput of output data from the same core.

    I wonder if there is a better place to report this issue (apparently there is no Issue tab on nRF Connect Github page).

  • Why, the example does exactly what it has to do.
    It has a known packet size and calculates packets per second that the buffers can take on the other end after receiving an acknowledgment.
    Of course this is maximum throughput - network core actually doing something with the packets will make it slower.
    It is one way signalling too, if you want to write a loopback you'll have to write your own test.

    What it does not do is use zero copy transfers, which could make it faster still.
    Also it can use ICMsg backend and not RPMsg backend if you pick the different configuration.

  • I think that there is a subtle difference between what you are explaining (and that it actually does), and the "receiving speed of data coming from the other core", mostly because we are calculating the data output rate within the core. I mean, we are not reading the buffer in the network core and calculating the speed of the application core (and vice-versa), the example instead sends from the appcore and calculate the throughput within that core (and vice-versa). There is no actual exchange of the "p_payload" data between the cores, and for this reason, I think the example is misleading in some way: each core prints the speed of data coming out of the same core.

    Nevertheless, playing with the code I was able to exchange data between the cores, so the ticket can be closed. Thank you so much for the help provided!

Reply
  • I think that there is a subtle difference between what you are explaining (and that it actually does), and the "receiving speed of data coming from the other core", mostly because we are calculating the data output rate within the core. I mean, we are not reading the buffer in the network core and calculating the speed of the application core (and vice-versa), the example instead sends from the appcore and calculate the throughput within that core (and vice-versa). There is no actual exchange of the "p_payload" data between the cores, and for this reason, I think the example is misleading in some way: each core prints the speed of data coming out of the same core.

    Nevertheless, playing with the code I was able to exchange data between the cores, so the ticket can be closed. Thank you so much for the help provided!

Children
No Data
Related