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