Skip to content

Commit 70393b3

Browse files
maje-embcfriedt
authored andcommitted
samples: subsys: ipc: Add a sample for using IPC Service
Demonstating usage of IPC Service. Multi-instance RPMsg was ued as a backed for IPC Service. Signed-off-by: Marcin Jeliński <[email protected]>
1 parent 20d63b0 commit 70393b3

File tree

10 files changed

+562
-0
lines changed

10 files changed

+562
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (c) 2021 Nordic Semiconductor ASA
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
6+
cmake_minimum_required(VERSION 3.13.1)
7+
8+
set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipc_service_remote-prefix/src/ipc_service_remote-build/zephyr)
9+
10+
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")
11+
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
12+
else()
13+
message(FATAL_ERROR "${BOARD} is not supported for this sample")
14+
endif()
15+
16+
message(INFO " ${BOARD} compile as Master in this sample")
17+
18+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
19+
project(ipc_service)
20+
21+
enable_language(C ASM)
22+
23+
target_sources(app PRIVATE src/main.c)
24+
25+
include(ExternalProject)
26+
27+
ExternalProject_Add(
28+
ipc_service_remote
29+
SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote
30+
INSTALL_COMMAND "" # This particular build system has no install command
31+
CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE}
32+
CMAKE_CACHE_ARGS -DDTC_OVERLAY_FILE:STRING=${DTC_OVERLAY_FILE}
33+
BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}"
34+
# NB: Do we need to pass on more CMake variables?
35+
BUILD_ALWAYS True
36+
)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
.. _IPC_Service_sample:
2+
3+
IPC Service
4+
###########
5+
6+
Overview
7+
********
8+
9+
IPC Service is an abstraction layer.
10+
It needs the corresponding backend registered for proper operation.
11+
You can use any IPC mechanism as a backend.
12+
In this sample, it is a multiple instance of RPMsg.
13+
This sample demonstrates how to integrate IPC Service with Zephyr.
14+
15+
Building the application for nrf5340dk_nrf5340_cpuapp
16+
*****************************************************
17+
18+
.. zephyr-app-commands::
19+
:zephyr-app: samples/subsys/ipc/ipc_service
20+
:board: nrf5340dk_nrf5340_cpuapp
21+
:goals: debug
22+
23+
Open a serial terminal (for example Minicom or PuTTY) and connect the board with the
24+
following settings:
25+
26+
- Speed: 115200
27+
- Data: 8 bits
28+
- Parity: None
29+
- Stop bits: 1
30+
31+
When you reset the development kit, the following messages (one for master and one for remote) will appear on the corresponding serial ports:
32+
33+
.. code-block:: console
34+
35+
*** Booting Zephyr OS build v2.6.0-rc3-5-g026dfb6f1b71 ***
36+
37+
IPC Service [master 1] demo started
38+
39+
IPC Service [master 2] demo started
40+
Master [1] received a message: 1
41+
Master [2] received a message: 1
42+
Master [1] received a message: 3
43+
Master [2] received a message: 3
44+
45+
...
46+
Master [1] received a message: 99
47+
IPC Service [master 1] demo ended.
48+
Master [2] received a message: 99
49+
IPC Service [master 2] demo ended.
50+
51+
52+
.. code-block:: console
53+
54+
*** Booting Zephyr OS build v2.6.0-rc3-5-g026dfb6f1b71 ***
55+
56+
IPC Service [remote 1] demo started
57+
58+
IPC Service [remote 2] demo started
59+
Remote [1] received a message: 0
60+
Remote [2] received a message: 0
61+
Remote [1] received a message: 2
62+
Remote [2] received a message: 2
63+
Remote [1] received a message: 4
64+
Remote [2] received a message: 4
65+
...
66+
Remote [1] received a message: 98
67+
IPC Service [remote 1] demo ended.
68+
Remote [2] received a message: 98
69+
IPC Service [remote 2] demo ended.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
CONFIG_BOARD_ENABLE_CPUNET=y
2+
3+
# Backend configuration for IPC Service
4+
CONFIG_IPM=y
5+
CONFIG_IPM_NRFX=y
6+
7+
# Enable all needed IPM channels
8+
CONFIG_IPM_MSG_CH_0_ENABLE=y
9+
CONFIG_IPM_MSG_CH_1_ENABLE=y
10+
CONFIG_IPM_MSG_CH_2_ENABLE=y
11+
CONFIG_IPM_MSG_CH_3_ENABLE=y
12+
13+
# Configure all RX channels
14+
CONFIG_IPM_MSG_CH_0_RX=y
15+
CONFIG_IPM_MSG_CH_2_RX=y
16+
17+
# Configure all TX channels
18+
CONFIG_IPM_MSG_CH_1_TX=y
19+
CONFIG_IPM_MSG_CH_3_TX=y
20+
21+
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_1"
22+
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_0"
23+
CONFIG_RPMSG_MULTI_INSTANCE_2_IPM_TX_NAME="IPM_3"
24+
CONFIG_RPMSG_MULTI_INSTANCE_2_IPM_RX_NAME="IPM_2"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CONFIG_PRINTK=y
2+
CONFIG_IPM=y
3+
CONFIG_TIMESLICE_SIZE=1
4+
CONFIG_MAIN_STACK_SIZE=2048
5+
CONFIG_HEAP_MEM_POOL_SIZE=4096
6+
7+
# Configuration IPC Service
8+
CONFIG_IPC_SERVICE=y
9+
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE=y
10+
11+
# Configuration backend for IPC Service
12+
CONFIG_OPENAMP=y
13+
CONFIG_OPENAMP_SLAVE=n
14+
15+
CONFIG_RPMSG_MULTI_INSTANCE_MASTER=y
16+
CONFIG_RPMSG_MULTI_INSTANCES_NO=2
17+
18+
CONFIG_LOG=y
19+
CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) 2018-2021 Nordic Semiconductor ASA
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
6+
cmake_minimum_required(VERSION 3.13.1)
7+
8+
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet")
9+
message(INFO " ${BOARD} compile as slave in this sample")
10+
else()
11+
message(FATAL_ERROR "${BOARD} is not supported for this sample")
12+
endif()
13+
14+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
15+
project(ipc_service_remote)
16+
17+
target_sources(app PRIVATE src/main.c)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Backend configuration for IPC Service
2+
CONFIG_IPM=y
3+
CONFIG_IPM_NRFX=y
4+
5+
# Enable all needed IPM channels
6+
CONFIG_IPM_MSG_CH_0_ENABLE=y
7+
CONFIG_IPM_MSG_CH_1_ENABLE=y
8+
CONFIG_IPM_MSG_CH_2_ENABLE=y
9+
CONFIG_IPM_MSG_CH_3_ENABLE=y
10+
11+
# Configure all RX channels
12+
CONFIG_IPM_MSG_CH_1_RX=y
13+
CONFIG_IPM_MSG_CH_3_RX=y
14+
15+
# Configure all TX channels
16+
CONFIG_IPM_MSG_CH_0_TX=y
17+
CONFIG_IPM_MSG_CH_2_TX=y
18+
19+
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_0"
20+
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_1"
21+
CONFIG_RPMSG_MULTI_INSTANCE_2_IPM_TX_NAME="IPM_2"
22+
CONFIG_RPMSG_MULTI_INSTANCE_2_IPM_RX_NAME="IPM_3"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CONFIG_STDOUT_CONSOLE=n
2+
CONFIG_PRINTK=n
3+
CONFIG_IPM=y
4+
CONFIG_HEAP_MEM_POOL_SIZE=4096
5+
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
6+
7+
# Configuration IPC Service
8+
CONFIG_IPC_SERVICE=y
9+
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE=y
10+
11+
# Configuration backend for IPC Service
12+
CONFIG_OPENAMP=y
13+
CONFIG_OPENAMP_MASTER=n
14+
15+
CONFIG_RPMSG_MULTI_INSTANCE_REMOTE=y
16+
CONFIG_RPMSG_MULTI_INSTANCES_NO=2
17+
18+
CONFIG_LOG=y
19+
CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright (c) 2021 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr.h>
8+
#include <drivers/ipm.h>
9+
#include <sys/printk.h>
10+
#include <device.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
15+
#include <ipc/ipc_service.h>
16+
17+
#define APP_TASK_STACK_SIZE 1024
18+
19+
K_THREAD_STACK_DEFINE(thread_stack_1, APP_TASK_STACK_SIZE);
20+
K_THREAD_STACK_DEFINE(thread_stack_2, APP_TASK_STACK_SIZE);
21+
22+
static struct k_thread thread_data_1;
23+
static struct k_thread thread_data_2;
24+
25+
static volatile uint8_t received_data_1;
26+
static volatile uint8_t received_data_2;
27+
28+
static K_SEM_DEFINE(bound_ept1_sem, 0, 1);
29+
static K_SEM_DEFINE(bound_ept2_sem, 0, 1);
30+
31+
static K_SEM_DEFINE(data_rx1_sem, 0, 1);
32+
static K_SEM_DEFINE(data_rx2_sem, 0, 1);
33+
34+
static struct ipc_ept *ept_1;
35+
static struct ipc_ept *ept_2;
36+
37+
static void ept_bound_1(void *priv)
38+
{
39+
k_sem_give(&bound_ept1_sem);
40+
}
41+
42+
static void ept_recv_1(const void *data, size_t len, void *priv)
43+
{
44+
received_data_1 = *((uint8_t *) data);
45+
k_sem_give(&data_rx1_sem);
46+
}
47+
48+
static void ept_error_1(const char *message, void *priv)
49+
{
50+
printk("Endpoint [1] error: %s", message);
51+
}
52+
53+
static void ept_bound_2(void *priv)
54+
{
55+
k_sem_give(&bound_ept2_sem);
56+
}
57+
58+
static void ept_recv_2(const void *data, size_t len, void *priv)
59+
{
60+
received_data_2 = *((uint8_t *) data);
61+
k_sem_give(&data_rx2_sem);
62+
}
63+
64+
static void ept_error_2(const char *message, void *priv)
65+
{
66+
printk("Endpoint [2] error: %s", message);
67+
}
68+
69+
void app_task_1(void *arg1, void *arg2, void *arg3)
70+
{
71+
ARG_UNUSED(arg1);
72+
ARG_UNUSED(arg2);
73+
ARG_UNUSED(arg3);
74+
int status = 0;
75+
uint8_t message = 0U;
76+
77+
printk("\r\nIPC Service [remote 1] demo started\r\n");
78+
79+
static struct ipc_ept_cfg ept_cfg = {
80+
.name = "ep_1",
81+
.prio = 0,
82+
.priv = NULL,
83+
.cb = {
84+
.bound = ept_bound_1,
85+
.received = ept_recv_1,
86+
.error = ept_error_1,
87+
},
88+
};
89+
90+
status = ipc_service_register_endpoint(&ept_1, &ept_cfg);
91+
if (status < 0) {
92+
printk("ipc_service_register_endpoint failed %d\n", status);
93+
return;
94+
}
95+
96+
k_sem_take(&bound_ept1_sem, K_FOREVER);
97+
98+
while (message < 99) {
99+
k_sem_take(&data_rx1_sem, K_FOREVER);
100+
message = received_data_1;
101+
printk("Remote [1] received a message: %d\n", message);
102+
103+
message++;
104+
status = ipc_service_send(ept_1, &message, sizeof(message));
105+
if (status < 0) {
106+
printk("send_message(%d) failed with status %d\n",
107+
message, status);
108+
break;
109+
}
110+
}
111+
112+
printk("IPC Service [remote 1] demo ended.\n");
113+
}
114+
115+
void app_task_2(void *arg1, void *arg2, void *arg3)
116+
{
117+
ARG_UNUSED(arg1);
118+
ARG_UNUSED(arg2);
119+
ARG_UNUSED(arg3);
120+
int status = 0;
121+
uint8_t message = 0U;
122+
123+
printk("\r\nIPC Service [remote 2] demo started\r\n");
124+
125+
static struct ipc_ept_cfg ept_cfg = {
126+
.name = "ep_2",
127+
.prio = 0,
128+
.priv = NULL,
129+
.cb = {
130+
.bound = ept_bound_2,
131+
.received = ept_recv_2,
132+
.error = ept_error_2,
133+
},
134+
};
135+
136+
status = ipc_service_register_endpoint(&ept_2, &ept_cfg);
137+
138+
if (status < 0) {
139+
printk("ipc_service_register_endpoint failed %d\n", status);
140+
return;
141+
}
142+
143+
k_sem_take(&bound_ept2_sem, K_FOREVER);
144+
145+
while (message < 99) {
146+
k_sem_take(&data_rx2_sem, K_FOREVER);
147+
message = received_data_2;
148+
printk("Remote [2] received a message: %d\n", message);
149+
150+
message++;
151+
status = ipc_service_send(ept_2, &message, sizeof(message));
152+
if (status < 0) {
153+
printk("send_message(%d) failed with status %d\n",
154+
message, status);
155+
break;
156+
}
157+
}
158+
159+
printk("IPC Service [remote 2] demo ended.\n");
160+
}
161+
162+
void main(void)
163+
{
164+
k_thread_create(&thread_data_1, thread_stack_1, APP_TASK_STACK_SIZE,
165+
(k_thread_entry_t)app_task_1,
166+
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
167+
168+
k_thread_create(&thread_data_2, thread_stack_2, APP_TASK_STACK_SIZE,
169+
(k_thread_entry_t)app_task_2,
170+
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
171+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
sample:
2+
description: This app provides an example of how to integrate
3+
IPC Service with Zephyr.
4+
name: IPC Service example integration
5+
tests:
6+
sample.ipc.rpmsg_service.nrf:
7+
platform_allow: nrf5340dk_nrf5340_cpuapp
8+
integration_platforms:
9+
- nrf5340dk_nrf5340_cpuapp
10+
tags: ipm
11+
build_only: true

0 commit comments

Comments
 (0)