This is the documentation for the latest (main) development branch. If you are looking for the documentation of previous releases, use the drop-down menu on the left and select the desired version.

OpenAMP multi services sample Application using resource table

Overview

This application demonstrates how to use OpenAMP with Zephyr based on a resource table. It is designed to respond to the:

This sample implementation is compatible with platforms that embed a Linux kernel OS on the main processor and a Zephyr application on the co-processor.

Tested on board:

Building the application

Zephyr

west build -b <target board> openamp-system-reference/examples/zephyr/rpmsg_multi_services

Linux

Enable:

  • the SAMPLE_RPMSG_CLIENT configuration to build and install the rpmsg_client_sample.ko module on the target,

  • the RPMSG_TTY configuration to build and install the rpmsg_tty.ko module on the target

  • the RPMSG_CHAR configuration to build and install the rpmsg_char.ko module on the target

  • build and install the rpmsg-utils binaries

Running the sample

Zephyr console

Open a serial terminal (minicom, putty, etc.) and connect the board with the following settings:

  • Speed: 115200

  • Data: 8 bits

  • Parity: None

  • Stop bits: 1

Reset the board.

Linux console

Open a Linux shell (minicom, ssh, etc.)

  • Insert a module into the Linux Kernel:

root@linuxshell: insmod rpmsg_client_sample.ko rpmsg_tty.ko rpmsg_char.ko rpmsg_ctrl.ko
  • Start the demo environment

First copy the rpmsg_multi_services.elf file on the target rrottfs in /lib/firmware folder. Then start the firmware:

root@linuxshell: echo rpmsg_multi_services.elf > /sys/class/remoteproc/remoteproc0/firmware
root@linuxshell: echo start >/sys/class/remoteproc/remoteproc0/state

Result on Zephyr console on boot

The following messages will appear on the corresponding Zephyr console

[   54.495343] virtio_rpmsg_bus virtio0: rpmsg host is online
[   54.500044] virtio_rpmsg_bus virtio0: creating channel rpmsg-client-sample addr 0x400
[   54.507923] virtio_rpmsg_bus virtio0: creating channel rpmsg-tty addr 0x401
[   54.514795] virtio_rpmsg_bus virtio0: creating channel rpmsg-raw addr 0x402
[   54.548954] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: new channel: 0x402 -> 0x400!
[   54.557337] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 1 (src: 0x400)
[   54.565532] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 2 (src: 0x400)
[   54.581090] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 3 (src: 0x400)
[   54.588699] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 4 (src: 0x400)
[   54.599424] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 5 (src: 0x400)
...

This inform that following rpmsg channels devices have been created:

  • a rpmsg-client-sample device

    root@linuxshell: dmesg
    ...
    [   54.500044] virtio_rpmsg_bus virtio0: creating channel rpmsg-client-sample addr 0x400
    ...
    
  • a rpmsg-tty device

    root@linuxshell: ls /dev/ttyRPMSG*
    /dev/ttyRPMSG0
    
  • a rpmsg-raw device

    root@linuxshell: ls /dev/rpmsg?
    /dev/rpmsg0
    

The following messages will appear on the corresponding Zephyr console or in the remoteproc trace buffer depending on the Hardware.

root@linuxshell:  cat /sys/kernel/debug/remoteproc/remoteproc0/trace0
*** Booting Zephyr OS build zephyr-v3.2.0-1-g6b49008b6b83  ***
Starting application threads!

OpenAMP[remote]  linux responder demo started

OpenAMP[remote] Linux sample client responder started

OpenAMP[remote] Linux tty responder started

OpenAMP[remote] Linux raw data responder started

OpenAMP[remote] create a endpoint with address and dest_address set to 0x1
OpenAMP Linux sample client responder ended

Demo 1: rpmsg-client-sample device

Principle

This demo is automatically run when the co-processor firmware is started. It confirms that the rpmsg and virtio protocols are working properly. The Zephyr requests the creation of the rpmsg-client-sample channel to the Linux rpmsg framework using the “name service announcement” rpmsg. On message reception the Linux rpmsg bus creates an associated device and probes the rpmsg-client-sample driver. The Linux rpmsg-client-sample driver sent 100 messages to the remote processor, which answers to each message. After answering to each rpmsgs the Zephyr destroys the channel.

Associated traces

[   54.548954] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: new channel: 0x402 -> 0x400!
[   54.557337] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 1 (src: 0x400)
[   54.565532] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 2 (src: 0x400)

  ...

[   55.436401] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 99 (src: 0x400)
[   55.445343] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 100 (src: 0x400)
[   55.454280] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: goodbye!
[   55.461424] virtio_rpmsg_bus virtio0: destroying channel rpmsg-client-sample addr 0x400
[   55.469707] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: rpmsg sample client driver is removed

Demo 2: rpmsg-tty device

Principle

This channel allows to create a /dev/ttyRPMSGx for terminal based communication with Zephyr.

Demo

  1. Check presence of the /dev/ttyRPMSG0

By default the Zephyr has created a rpmsg-tty channel

[   54.507923] virtio_rpmsg_bus virtio0: creating channel rpmsg-tty addr 0x401
root@linuxshell: ls /dev/ttyRPMSG*
/dev/ttyRPMSG0
  1. Send and receive messages on /dev/ttyRPMSG0

The zephyr is programmed to resent received messages with a prefixed “TTY 0: “, 0 is the instance of the tty link

root@linuxshell: cat /dev/ttyRPMSG0 &
root@linuxshell: echo "Hello Zephyr" >/dev/ttyRPMSG0
TTY 0: Hello Zephyr
root@linuxshell: echo "Goodbye Zephyr" >/dev/ttyRPMSG0
TTY 0: Goodbye Zephyr

Demo 3: dynamic creation/release of a rpmsg-tty device

Principle

This demo is based on the rpmsg_char restructuring series not yet upstreamed. This series de-correlates the /dev/rpmsg_ctrl from the rpmsg_char device and then introduces 2 new rpmsg IOCtrls:

  • RPMSG_CREATE_DEV_IOCTL : to create a local rpmsg device and to send a name service creation announcement to the remote processor

  • RPMSG_RELEASE_DEV_IOCTL: release the local rpmsg device and to send a name service destroy announcement to the remote processor

Demo

  1. Prerequisite

Due to a limitation in the rpmsg protocol, the zephyr does not know the existence of the /dev/ttyRPMG0 until the Linux sends it a first message. Creating a new channel before this first one is well establish leads to bad endpoints association. To avoid this, just send a message on /dev/ttyRPMSG0

root@linuxshell: cat /dev/ttyRPMSG0 &
root@linuxshell: echo "Hello Zephyr" >/dev/ttyRPMSG0
TTY 0: Hello Zephyr

Download rpmsg-utils tools relying on the /dev/rpmsg_ctrl, and compile it in an arm environment using make instruction and install it on target.

optional: enable rpmsg bus trace to observe RPmsg in kernel trace:

root@linuxshell: echo -n 'file virtio_rpmsg_bus.c +p' > /sys/kernel/debug/dynamic_debug/control
  1. create a new TTY channel

Create a rpmsg-tty channel from Linux with local address set to 257 and undefined remote address -1.

Note

Current Linux implementation has a limitation. When it initiates a name service announcement, It is not able to associate the remote endpoint to the created channel. Following patch has to be applied on top waiting a upstreamed solution:

<https://lore.kernel.org/lkml/20220316153001.662422-1-arnaud.pouliquen@foss.st.com/>

root@linuxshell: ./rpmsg_export_dev /dev/rpmsg_ctrl0 rpmsg-tty 257 -1

The /dev/ttyRPMSG1 is created

root@linuxshell: ls /dev/ttyRPMSG*
/dev/ttyRPMSG0  /dev/ttyRPMSG1

A name service announcement has been sent to Zephyr, which has created a local endpoint (@ 0x400), and sent a “bound” message to the /dev/ttyRPMG1 (@ 257)

root@linuxshell: dmesg
[  115.757439] rpmsg_tty virtio0.rpmsg-tty.257.-1: TX From 0x101, To 0x35, Len 40, Flags 0, Reserved 0
[  115.757497] rpmsg_virtio TX: 01 01 00 00 35 00 00 00 00 00 00 00 28 00 00 00  ....5.......(...
[  115.757514] rpmsg_virtio TX: 72 70 6d 73 67 2d 74 74 79 00 00 00 00 00 00 00  rpmsg-tty.......
[  115.757528] rpmsg_virtio TX: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
[  115.757540] rpmsg_virtio TX: 01 01 00 00 00 00 00 00                          ........
[  115.757568] remoteproc remoteproc0: kicking vq index: 1
[  115.757590] stm32-ipcc 4c001000.mailbox: stm32_ipcc_send_data: chan:1
[  115.757850] stm32-ipcc 4c001000.mailbox: stm32_ipcc_tx_irq: chan:1 tx
[  115.757906] stm32-ipcc 4c001000.mailbox: stm32_ipcc_rx_irq: chan:0 rx
[  115.757969] remoteproc remoteproc0: vq index 0 is interrupted
[  115.757994] virtio_rpmsg_bus virtio0: From: 0x400, To: 0x101, Len: 6, Flags: 0, Reserved: 0
[  115.758022] rpmsg_virtio RX: 00 04 00 00 01 01 00 00 00 00 00 00 06 00 00 00  ................
[  115.758035] rpmsg_virtio RX: 62 6f 75 6e 64 00                                bound.
[  115.758077] virtio_rpmsg_bus virtio0: Received 1 messages
  1. Play with /dev/ttyRPMSG0 and /dev/ttyRPMSG1

root@linuxshell: cat /dev/ttyRPMSG0 &
root@linuxshell: cat /dev/ttyRPMSG1 &
root@linuxshell: echo hello dev0 >/dev/ttyRPMSG0
TTY 0: hello dev0
root@linuxshell: echo hello dev1 >/dev/ttyRPMSG1
TTY 1: hello dev1
  1. Destroy RPMSG TTY devices

Destroy the /dev/ttyRPMSG1

root@linuxshell: ./rpmsg_export_dev /dev/rpmsg_ctrl0 -d rpmsg-tty 257 -1

Destroy the /dev/ttyRPMSG0 * Get the source address

root@linuxshell: cat /sys/bus/rpmsg/devices/virtio0.rpmsg-tty.-1.*/src
0x402
  • Destroy the /dev/ttyRPMSG0 specifying the address 1026 (0x402)

root@linuxshell: ./rpmsg_export_dev /dev/rpmsg_ctrl0 -d rpmsg-tty 1026 -1

The /dev/ttyRPMGx devices no more exists

Demo 4: rpmsg-char device

Principle

This channel allows to create a /dev/rpmsgX for character device based communication with Zephyr.

Demo

  1. Prerequisite

Download rpmsg-utils tools relying on the /dev/rpmsg_ctrl, an compile it in an arm environment using make instruction and install it on target

optional: enable rpmsg bus trace to observe rp messages in kernel trace:

echo -n 'file virtio_rpmsg_bus.c +p' > /sys/kernel/debug/dynamic_debug/control
  1. Check presence of the /dev/rpmsg0

By default the Zephyr has created a rpmsg-raw channel

[   54.514795] virtio_rpmsg_bus virtio0: creating channel rpmsg-raw addr 0x402
  1. Check device exists

root@linuxshell: ls /dev/rpmsg?
/dev/rpmsg0
  1. Send and receive messages on /dev/rpmsg0

The zephyr is programmed to resent received message with a prefixed “from ept 0x0402: “, 0x0402 is the zephyr endpoint address

root@linuxshell: ./rpmsg_ping /dev/rpmsg0
message for /dev/rpmsg0: "from ept 0x0402: ping /dev/rpmsg0"

Demo 5: Multi endpoints demo using rpmsg-ctrl device

Principle

Use the rpmsg_ctrl RPMSG_CREATE_EPT_IOCTL IoCtrl to instantiate endpoints on Linux side. Theses endpoints will not be associated to a channel but will communicate with a predefined remote proc endpoint. For each endpoint created, a /dev/rpmsg sysfs interface will be created On Zephyr side, an endpoint with a prefixed address 0x1 has been created. When it receives a message it re-sends a the message to the Linux sender endpoint, prefixed by “from ept 0x0001:”

Demo

  1. Prerequisite

Download rpmsg-util tools relying on the /dev/rpmsg_ctrl, an compile it in an arm environment using make instruction and install it on target

optional: enable rpmsg bus trace to observe rp messages in kernel trace:

echo -n 'file virtio_rpmsg_bus.c +p' > /sys/kernel/debug/dynamic_debug/control
  1. Check presence of the /dev/rpmsg0

By default the Zephyr has created a rpmsg-raw channel

[   54.514795] virtio_rpmsg_bus virtio0: creating channel rpmsg-raw addr 0x402
  1. Check device exists

root@linuxshell: ls /dev/rpmsg*
/dev/rpmsg0       /dev/rpmsg_ctrl0
  1. Create 3 new endpoints

root@linuxshell: ./rpmsg_export_ept /dev/rpmsg_ctrl0 my_endpoint1 100 1
root@linuxshell: ./rpmsg_export_ept /dev/rpmsg_ctrl0 my_endpoint2 101 1
root@linuxshell: ./rpmsg_export_ept /dev/rpmsg_ctrl0 my_endpoint2 103 1
root@linuxshell: ls /dev/rpmsg?
/dev/rpmsg0  /dev/rpmsg1  /dev/rpmsg2  /dev/rpmsg3
  1. Test them

root@linuxshell: ./rpmsg_ping  /dev/rpmsg0
message for /dev/rpmsg0: "from ept 0x0402: ping /dev/rpmsg0"
root@linuxshell: ./rpmsg_ping  /dev/rpmsg1
message for /dev/rpmsg1: "from ept 0x0001: ping /dev/rpmsg1"
root@linuxshell: ./rpmsg_ping  /dev/rpmsg2
message for /dev/rpmsg2: "from ept 0x0001: ping /dev/rpmsg2"
root@linuxshell: ./rpmsg_ping  /dev/rpmsg3
message for /dev/rpmsg3: "from ept 0x0001: ping /dev/rpmsg3"
  1. Destroy them

root@linuxshell: ./rpmsg_destroy_ept /dev/rpmsg1
root@linuxshell: ./rpmsg_destroy_ept /dev/rpmsg2
root@linuxshell: ./rpmsg_destroy_ept /dev/rpmsg3
root@linuxshell: ls /dev/rpmsg?
/dev/rpmsg0