ipc_service: samples: Add sample that uses icmsg backend
Add sample to demonstrate newly introduced backend (icmsg). Signed-off-by: Emil Obalski <emil.obalski@nordicsemi.no>
This commit is contained in:
parent
78aa0fce6b
commit
66a8d5baef
11 changed files with 456 additions and 0 deletions
32
samples/subsys/ipc/ipc_service/icmsg/CMakeLists.txt
Normal file
32
samples/subsys/ipc/ipc_service/icmsg/CMakeLists.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipc_service_remote-prefix/src/ipc_service_remote-build/zephyr)
|
||||
|
||||
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")
|
||||
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
|
||||
else()
|
||||
message(FATAL_ERROR "${BOARD} is not supported for this sample")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(ipc_service_host)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
ipc_service_remote
|
||||
SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote
|
||||
INSTALL_COMMAND "" # This particular build system has no install command
|
||||
CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE}
|
||||
BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}"
|
||||
# NB: Do we need to pass on more CMake variables?
|
||||
BUILD_ALWAYS True
|
||||
)
|
|
@ -0,0 +1,2 @@
|
|||
CONFIG_BOARD_ENABLE_CPUNET=y
|
||||
CONFIG_MBOX_NRFX_IPC=y
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/delete-node/ &ipc0;
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
/delete-property/ zephyr,ipc_shm;
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
/delete-node/ memory@20070000;
|
||||
|
||||
sram_tx: memory@20070000 {
|
||||
reg = <0x20070000 0x0800>;
|
||||
};
|
||||
|
||||
sram_rx: memory@20078000 {
|
||||
reg = <0x20078000 0x0800>;
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
peripheral@50000000 {
|
||||
/delete-node/ ipc@2a000;
|
||||
|
||||
mbox: mbox@2a000 {
|
||||
compatible = "nordic,mbox-nrf-ipc";
|
||||
reg = <0x2a000 0x1000>;
|
||||
tx-mask = <0x0000ffff>;
|
||||
rx-mask = <0x0000ffff>;
|
||||
interrupts = <42 NRF_DEFAULT_IRQ_PRIORITY>;
|
||||
#mbox-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ipc0: ipc0 {
|
||||
compatible = "zephyr,ipc-icmsg";
|
||||
tx-region = <&sram_tx>;
|
||||
rx-region = <&sram_rx>;
|
||||
mboxes = <&mbox 0>, <&mbox 1>;
|
||||
mbox-names = "tx", "rx";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
7
samples/subsys/ipc/ipc_service/icmsg/prj.conf
Normal file
7
samples/subsys/ipc/ipc_service/icmsg/prj.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
CONFIG_PRINTK=y
|
||||
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_ICMSG=y
|
||||
CONFIG_MBOX=y
|
||||
|
||||
CONFIG_LOG=y
|
12
samples/subsys/ipc/ipc_service/icmsg/remote/CMakeLists.txt
Normal file
12
samples/subsys/ipc/ipc_service/icmsg/remote/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(ipc_service_remote)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
|
@ -0,0 +1 @@
|
|||
CONFIG_MBOX_NRFX_IPC=y
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/delete-node/ &ipc0;
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
/delete-property/ zephyr,ipc_shm;
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
/delete-node/ memory@20070000;
|
||||
|
||||
sram_rx: memory@20070000 {
|
||||
reg = <0x20070000 0x0800>;
|
||||
};
|
||||
|
||||
sram_tx: memory@20078000 {
|
||||
reg = <0x20078000 0x0800>;
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
/delete-node/ ipc@41012000;
|
||||
|
||||
mbox: mbox@41012000 {
|
||||
compatible = "nordic,mbox-nrf-ipc";
|
||||
reg = <0x41012000 0x1000>;
|
||||
tx-mask = <0x0000ffff>;
|
||||
rx-mask = <0x0000ffff>;
|
||||
interrupts = <18 NRF_DEFAULT_IRQ_PRIORITY>;
|
||||
#mbox-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
ipc0: ipc0 {
|
||||
compatible = "zephyr,ipc-icmsg";
|
||||
tx-region = <&sram_tx>;
|
||||
rx-region = <&sram_rx>;
|
||||
mboxes = <&mbox 0>, <&mbox 1>;
|
||||
mbox-names = "rx", "tx";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
7
samples/subsys/ipc/ipc_service/icmsg/remote/prj.conf
Normal file
7
samples/subsys/ipc/ipc_service/icmsg/remote/prj.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
CONFIG_PRINTK=y
|
||||
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_ICMSG=y
|
||||
CONFIG_MBOX=y
|
||||
|
||||
CONFIG_LOG=y
|
144
samples/subsys/ipc/ipc_service/icmsg/remote/src/main.c
Normal file
144
samples/subsys/ipc/ipc_service/icmsg/remote/src/main.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
|
||||
#include <ipc/ipc_service.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(remote, LOG_LEVEL_INF);
|
||||
|
||||
#define MLEN_0 40
|
||||
|
||||
struct data_packet {
|
||||
unsigned char message;
|
||||
unsigned char data[100];
|
||||
};
|
||||
|
||||
|
||||
K_SEM_DEFINE(bound_sem, 0, 1);
|
||||
|
||||
static void ep_bound(void *priv)
|
||||
{
|
||||
k_sem_give(&bound_sem);
|
||||
LOG_INF("Ep bounded");
|
||||
}
|
||||
|
||||
static void ep_recv(const void *data, size_t len, void *priv)
|
||||
{
|
||||
char received_data = *((char *)data);
|
||||
static char expected_message = 'a';
|
||||
static uint16_t expected_len = MLEN_0;
|
||||
|
||||
static unsigned long long cnt;
|
||||
static unsigned int stats_every;
|
||||
static uint32_t start;
|
||||
static unsigned int err;
|
||||
|
||||
if (start == 0) {
|
||||
start = k_uptime_get_32();
|
||||
}
|
||||
|
||||
if (received_data != expected_message) {
|
||||
err++;
|
||||
}
|
||||
|
||||
if (len != expected_len) {
|
||||
err++;
|
||||
}
|
||||
|
||||
expected_message++;
|
||||
expected_len++;
|
||||
|
||||
cnt += len;
|
||||
|
||||
if (expected_message > 'z') {
|
||||
if (stats_every++ > 50) {
|
||||
/* Print throuhput [Bytes/s]. Use printk not to overload CPU with logger.
|
||||
* Sample never reaches lower priority thread because of high throughput
|
||||
* (100% cpu load) so logging would not be able to handle messages in
|
||||
* deferred mode (immediate mode would be heavier than printk).
|
||||
*/
|
||||
printk("%llu\n", (1000*cnt)/(k_uptime_get_32() - start));
|
||||
stats_every = 0;
|
||||
}
|
||||
if (err) {
|
||||
printk("Unexpected message\n");
|
||||
}
|
||||
expected_message = 'a';
|
||||
}
|
||||
|
||||
if (expected_len > sizeof(struct data_packet)) {
|
||||
expected_len = MLEN_0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ipc_ept_cfg ep_cfg = {
|
||||
.cb = {
|
||||
.bound = ep_bound,
|
||||
.received = ep_recv,
|
||||
},
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct device *ipc0_instance;
|
||||
struct data_packet msg = {.message = 'A'};
|
||||
struct ipc_ept ep;
|
||||
int ret;
|
||||
|
||||
LOG_INF("IPC-service REMOTE demo started");
|
||||
|
||||
ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
|
||||
|
||||
ret = ipc_service_open_instance(ipc0_instance);
|
||||
if ((ret < 0) && (ret != -EALREADY)) {
|
||||
LOG_INF("ipc_service_open_instance() failure");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
|
||||
if (ret < 0) {
|
||||
printf("ipc_service_register_endpoint() failure");
|
||||
return ret;
|
||||
}
|
||||
|
||||
k_sem_take(&bound_sem, K_FOREVER);
|
||||
|
||||
uint16_t mlen = MLEN_0;
|
||||
|
||||
while (true) {
|
||||
ret = ipc_service_send(&ep, &msg, mlen);
|
||||
if (ret == -ENOMEM) {
|
||||
/* No space in the buffer. Retry. */
|
||||
continue;
|
||||
} else if (ret < 0) {
|
||||
LOG_ERR("send_message(%d) failed with ret %d", msg.message, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
msg.message++;
|
||||
if (msg.message > 'Z') {
|
||||
msg.message = 'A';
|
||||
}
|
||||
|
||||
mlen++;
|
||||
if (mlen > sizeof(struct data_packet)) {
|
||||
mlen = MLEN_0;
|
||||
}
|
||||
|
||||
/* Quasi minimal busy wait time which allows to continuosly send
|
||||
* data without -ENOMEM error code. The purpose is to test max
|
||||
* throughput. Determined experimentally.
|
||||
*/
|
||||
k_busy_wait(50);
|
||||
}
|
||||
|
||||
LOG_INF("IPC-service REMOTE demo ended.");
|
||||
|
||||
return 0;
|
||||
}
|
9
samples/subsys/ipc/ipc_service/icmsg/sample.yaml
Normal file
9
samples/subsys/ipc/ipc_service/icmsg/sample.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
sample:
|
||||
name: IPC Service example integration (icmsg backend)
|
||||
tests:
|
||||
sample.ipc.icmsg:
|
||||
platform_allow: nrf5340dk_nrf5340_cpuapp
|
||||
integration_platforms:
|
||||
- nrf5340dk_nrf5340_cpuapp
|
||||
tags: ipc
|
||||
build_only: true
|
144
samples/subsys/ipc/ipc_service/icmsg/src/main.c
Normal file
144
samples/subsys/ipc/ipc_service/icmsg/src/main.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
|
||||
#include <ipc/ipc_service.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(host, LOG_LEVEL_INF);
|
||||
|
||||
#define MLEN_0 40
|
||||
|
||||
struct data_packet {
|
||||
unsigned char message;
|
||||
unsigned char data[100];
|
||||
};
|
||||
|
||||
|
||||
K_SEM_DEFINE(bound_sem, 0, 1);
|
||||
|
||||
static void ep_bound(void *priv)
|
||||
{
|
||||
k_sem_give(&bound_sem);
|
||||
LOG_INF("Ep bounded");
|
||||
}
|
||||
|
||||
static void ep_recv(const void *data, size_t len, void *priv)
|
||||
{
|
||||
char received_data = *((char *)data);
|
||||
static char expected_message = 'A';
|
||||
static uint16_t expected_len = MLEN_0;
|
||||
|
||||
static unsigned long long cnt;
|
||||
static unsigned int stats_every;
|
||||
static uint32_t start;
|
||||
static unsigned int err;
|
||||
|
||||
if (start == 0) {
|
||||
start = k_uptime_get_32();
|
||||
}
|
||||
|
||||
if (received_data != expected_message) {
|
||||
err++;
|
||||
}
|
||||
|
||||
if (len != expected_len) {
|
||||
err++;
|
||||
}
|
||||
|
||||
expected_message++;
|
||||
expected_len++;
|
||||
|
||||
cnt += len;
|
||||
|
||||
if (expected_message > 'Z') {
|
||||
if (stats_every++ > 50) {
|
||||
/* Print throuhput [Bytes/s]. Use printk not to overload CPU with logger.
|
||||
* Sample never reaches lower priority thread because of high throughput
|
||||
* (100% cpu load) so logging would not be able to handle messages in
|
||||
* deferred mode (immediate mode would be heavier than printk).
|
||||
*/
|
||||
printk("%llu\n", (1000*cnt)/(k_uptime_get_32() - start));
|
||||
stats_every = 0;
|
||||
}
|
||||
if (err) {
|
||||
printk("Unexpected message\n");
|
||||
}
|
||||
expected_message = 'A';
|
||||
}
|
||||
|
||||
if (expected_len > sizeof(struct data_packet)) {
|
||||
expected_len = MLEN_0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ipc_ept_cfg ep_cfg = {
|
||||
.cb = {
|
||||
.bound = ep_bound,
|
||||
.received = ep_recv,
|
||||
},
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct device *ipc0_instance;
|
||||
struct data_packet msg = {.message = 'a'};
|
||||
struct ipc_ept ep;
|
||||
int ret;
|
||||
|
||||
LOG_INF("IPC-service HOST demo started");
|
||||
|
||||
ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
|
||||
|
||||
ret = ipc_service_open_instance(ipc0_instance);
|
||||
if ((ret < 0) && (ret != -EALREADY)) {
|
||||
LOG_INF("ipc_service_open_instance() failure");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
|
||||
if (ret < 0) {
|
||||
printf("ipc_service_register_endpoint() failure");
|
||||
return ret;
|
||||
}
|
||||
|
||||
k_sem_take(&bound_sem, K_FOREVER);
|
||||
|
||||
uint16_t mlen = MLEN_0;
|
||||
|
||||
while (true) {
|
||||
ret = ipc_service_send(&ep, &msg, mlen);
|
||||
if (ret == -ENOMEM) {
|
||||
/* No space in the buffer. Retry. */
|
||||
continue;
|
||||
} else if (ret < 0) {
|
||||
LOG_ERR("send_message(%d) failed with ret %d", msg.message, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
msg.message++;
|
||||
if (msg.message > 'z') {
|
||||
msg.message = 'a';
|
||||
}
|
||||
|
||||
mlen++;
|
||||
if (mlen > sizeof(struct data_packet)) {
|
||||
mlen = MLEN_0;
|
||||
}
|
||||
|
||||
/* Quasi minimal busy wait time which allows to continuosly send
|
||||
* data without -ENOMEM error code. The purpose is to test max
|
||||
* throughput. Determined experimentally.
|
||||
*/
|
||||
k_busy_wait(100);
|
||||
}
|
||||
|
||||
LOG_INF("IPC-service HOST demo ended.");
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue