The latest development version of this page may be more current than this released v2024.05.0 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