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!

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

  • When you say sample for CPUNET, it means that i should flash the example in the Network core and flash another, custom application in the Application core? So in the end I should write two main.c that needs to be built each with their own dependencies, am I getting it right?

  • You are mixing things up. An application is not the same as a main function or a module.

    You *can* build separate applications. You do not *have to*.
    By default, NRF Connect SDK build one multi-image application, with one image per core.
    There is also a possibility to build a bootloader as a separate image in an application, used most typically for DFU or similar update schemes.

    These are not necessarily separate in any way, they can share headers or other files, and certainly can share Zephyr or other parts of the SDK.

    There are multiple main functions in such an application and two or more separate hex files are merged together.

    One of the modules runs on CPUNET, the other runs on CPUAPP . Both are built at the same time in a multi-image application.

    There are also applications that run nothing on CPUNET or nothing on CPUAPP.
    (The example for multicore application in fact runs a big nothing on CPUAPP.)

    Now provided you want to run code on both, you will have to create two modules. They can be built separately as separate single image builds, which may mean they do not share any code (but they still can), or together as part of a multi-image build in which case they always share the SDK.

    This bit might help explaining the difference between an application and a module: developer.nordicsemi.com/.../ug_multi_image.html
    And this bit might explain the separate bootloaders: developer.nordicsemi.com/.../README.html

    The non-default separate application per core build is a bit harder to configure. You must ensure the bootloader settings are correct... It is not supported by Nordic.

  • Yes, I am very confused about how things work, and I hope to make things clear.

    I had a look at the link you provided me, and I went through the multicore example so that I can try to get it.

    What I'm getting is that the CMakeLists.txt in the aci folder tells Zephyr to build what is inside the cpunet folder for the Network core. In the example, we don't have anything written in the cpunet folder, but a Cmake that is pointing to the src/main.c. This can be possible because of the definition of a Zephyr module (module.yml). At this point I think I can write a main.c that will be pointed by the cpunet/CMakeLists.txt that execute whatever I want to execute in the Network Core.

    As naive as it may sounds, I'm just trying to figure out where to write code for the Network core and where to write code for the Application, then flashing everything in my board Smiley

  • The multicore example is indeed the way to go. Put whatever you want to run on the network core in the cpunet directory. If you want to run bluetooth, copy hci_rpmsg (which is also in samples) in there and start coding from that.

    Unless you want cpunet to just run Bluetooth. In which case using the default hci_rpmsg setup is the way to go.

    You can adjust the example later to work with Secure Bootloader if necessary.

    Be mindful that CPUNET has only 256 KB of flash and 64 KB of RAM by default. Changing that is possible but not too easy. Not a lot can fit in there. It also only has some hardware routed to it.
    See here for which hardware is available on cpunet: docs.zephyrproject.org/.../index.html

Related