Skip to content

Commit 10bcefa

Browse files
committed
samples: Add RTxxx AMP samples
Move CM33-HiFi4 memory split into a separate DT fragment. Add common structure for RTxxx AMP samples. Add amp_blink and amp_mbox samples. These samples are now configured only for the mimxrt685_evk, but are intended to support other NXP microcontrollers with HiFi * DSP cores instantiated at a later date. Signed-off-by: Vit Stanicek <[email protected]>
1 parent d6b0d2d commit 10bcefa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1324
-1
lines changed

boards/nxp/mimxrt685_evk/doc/index.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,8 @@ must be done in order for it to be functional. The ``nxp_rtxxx_adsp_ctrl``,
330330
instantiated in the RT685's CM33 domain, takes care of this. Power domains
331331
and clocks are set up upon it initialising. This is sufficient for
332332
attaching a debugger to the core. For the use in an AMP system, this driver
333-
handles code loading and run control.
333+
handles code loading and run control. AMP usecases are demonstrated in sample
334+
projects located in ``samples/boards/nxp/adsp/rtxxx``.
334335

335336
.. include:: ../../common/board-footer.rst
336337
:start-after: nxp-board-footer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
6+
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
7+
8+
project(amp_audio_loopback)
9+
target_sources(app PRIVATE src/main.c)
10+
11+
include("${CMAKE_CURRENT_LIST_DIR}/../common/adsp-load.cmake")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
.. zephyr:code-sample:: amp_audio_loopback
2+
:name: Audio output AMP sample.
3+
4+
AMP system example for NXP i.MX RTxxx platforms - audio loopback.
5+
6+
Overview
7+
********
8+
9+
This sample demonstrates the use of the DSP domains on supported NXP i.MX RTxxx
10+
platforms in an asymmetric multiprocessing (AMP) scenario. It's a sample with
11+
separate projects for Cortex-M and DSP domains, that are built together into a
12+
single resulting image using Sysbuild. The Cortex-M domain is responsible for
13+
setting up the DSP domain (clock and power setup, code load and start), the DSP
14+
domain is programmed to write a "hello world" message to the board's chosen
15+
console UART, initialise hardware responsible for audio playback and capture
16+
and, subsequently, perform simultaneous audio capture and playback
17+
(echo / loopback).
18+
19+
Building and Running
20+
********************
21+
22+
This sample can be built and started on supported boards as follows:
23+
24+
.. zephyr-app-commands::
25+
:zephyr-app: samples/boards/nxp/adsp/rtxxx/amp_audio_loopback
26+
:board: <board>
27+
:goals: build flash
28+
:build-args: --sysbuild
29+
:flash-args: -r jlink
30+
:compact:
31+
32+
Currently, these boards are supported:
33+
- ``mimxrt685_evk/mimxrt685s/cm33``
34+
35+
The use of J-Link firmware on integrated debug probes of those boards or a
36+
standalone J-Link probe is desired as the J-Link probes have the ability
37+
to directly debug the Xtensa-based DSP cores.
38+
39+
Sample output
40+
=============
41+
42+
.. code-block:: console
43+
44+
*** Booting Zephyr OS build v4.1.0-1857-g5a39ed584d81 ***
45+
Hello World! mimxrt685_evk/mimxrt685s/cm33
46+
[ARM] Starting DSP...
47+
*** Booting Zephyr OS build v4.1.0-1857-g5a39ed584d81 ***
48+
Hello World! mimxrt685_evk/mimxrt685s/hifi4
49+
[DSP] Streams started.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_INIT_AUDIO_PLL=y
2+
CONFIG_INIT_SYS_PLL=y
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <nxp/nxp_rt6xx_hifi4memsplit.dtsi>
8+
9+
&adsp {
10+
status = "okay";
11+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_NXP_RTXXX_ADSP_CTRL=y
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
6+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
7+
project(remote)
8+
9+
target_sources(app PRIVATE src/main.c)
10+
11+
include("${CMAKE_CURRENT_LIST_DIR}/../../common/remote-adsp-imgs.cmake")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
aliases {
9+
i2s-rx = &i2s0;
10+
i2s-tx = &i2s1;
11+
};
12+
};
13+
14+
&i3c0 {
15+
status = "okay";
16+
};
17+
18+
&i2s0 {
19+
status = "okay";
20+
};
21+
22+
&i2s1 {
23+
status = "okay";
24+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CONFIG_DMA=y
2+
CONFIG_I2S=y
3+
CONFIG_I2C=y
4+
CONFIG_I3C=y
5+
CONFIG_AUDIO=y
6+
CONFIG_AUDIO_CODEC=y
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Copyright (c) 2021 Nordic Semiconductor ASA
3+
* Copyright (c) 2025 NXP
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/audio/codec.h>
10+
#include <zephyr/sys/printk.h>
11+
#include <zephyr/drivers/i2s.h>
12+
#include <string.h>
13+
14+
#define I2S_RX_NODE DT_ALIAS(i2s_rx)
15+
#define I2S_TX_NODE DT_ALIAS(i2s_tx)
16+
17+
#define SAMPLE_FREQUENCY 48000
18+
#define SAMPLE_BIT_WIDTH 16
19+
#define BYTES_PER_SAMPLE sizeof(int16_t)
20+
#define NUMBER_OF_CHANNELS 2
21+
/* Such block length provides an echo with the delay of 100 ms. */
22+
#define SAMPLES_PER_BLOCK ((SAMPLE_FREQUENCY / 10) * NUMBER_OF_CHANNELS)
23+
#define INITIAL_BLOCKS 2
24+
#define TIMEOUT 1000
25+
26+
#define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
27+
#define BLOCK_COUNT (INITIAL_BLOCKS + 2)
28+
K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);
29+
30+
static bool configure_streams(const struct device *i2s_dev_rx,
31+
const struct device *i2s_dev_tx,
32+
const struct i2s_config *config)
33+
{
34+
int ret;
35+
36+
if (i2s_dev_rx == i2s_dev_tx) {
37+
ret = i2s_configure(i2s_dev_rx, I2S_DIR_BOTH, config);
38+
if (ret == 0) {
39+
return true;
40+
}
41+
/* -ENOSYS means that the RX and TX streams need to be
42+
* configured separately.
43+
*/
44+
if (ret != -ENOSYS) {
45+
printk("[DSP] Failed to configure streams: %d\n", ret);
46+
return false;
47+
}
48+
}
49+
50+
ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, config);
51+
if (ret < 0) {
52+
printk("[DSP] Failed to configure RX stream: %d\n", ret);
53+
return false;
54+
}
55+
56+
ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, config);
57+
if (ret < 0) {
58+
printk("[DSP] Failed to configure TX stream: %d\n", ret);
59+
return false;
60+
}
61+
62+
return true;
63+
}
64+
65+
static bool prepare_transfer(const struct device *i2s_dev_rx,
66+
const struct device *i2s_dev_tx)
67+
{
68+
int ret;
69+
70+
for (int i = 0; i < INITIAL_BLOCKS; ++i) {
71+
void *mem_block;
72+
73+
ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
74+
if (ret < 0) {
75+
printk("[DSP] Failed to allocate TX block %d: %d\n", i, ret);
76+
return false;
77+
}
78+
79+
memset(mem_block, 0, BLOCK_SIZE);
80+
81+
ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
82+
if (ret < 0) {
83+
printk("[DSP] Failed to write block %d: %d\n", i, ret);
84+
return false;
85+
}
86+
}
87+
88+
return true;
89+
}
90+
91+
static bool trigger_command(const struct device *i2s_dev_rx,
92+
const struct device *i2s_dev_tx,
93+
enum i2s_trigger_cmd cmd)
94+
{
95+
int ret;
96+
97+
if (i2s_dev_rx == i2s_dev_tx) {
98+
ret = i2s_trigger(i2s_dev_rx, I2S_DIR_BOTH, cmd);
99+
if (ret == 0) {
100+
return true;
101+
}
102+
/* -ENOSYS means that commands for the RX and TX streams need
103+
* to be triggered separately.
104+
*/
105+
if (ret != -ENOSYS) {
106+
printk("[DSP] Failed to trigger command %d: %d\n", cmd, ret);
107+
return false;
108+
}
109+
}
110+
111+
ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
112+
if (ret < 0) {
113+
printk("[DSP] Failed to trigger command %d on RX: %d\n", cmd, ret);
114+
return false;
115+
}
116+
117+
ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, cmd);
118+
if (ret < 0) {
119+
printk("[DSP] Failed to trigger command %d on TX: %d\n", cmd, ret);
120+
return false;
121+
}
122+
123+
return true;
124+
}
125+
126+
int main(void)
127+
{
128+
const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_RX_NODE);
129+
const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
130+
const struct device *const codec_dev = DEVICE_DT_GET(DT_NODELABEL(audio_codec));
131+
struct i2s_config config;
132+
struct audio_codec_cfg audio_cfg;
133+
134+
printk("Hello World! %s\n", CONFIG_BOARD_TARGET);
135+
136+
if (!device_is_ready(i2s_dev_rx)) {
137+
printk("[DSP] %s is not ready\n", i2s_dev_rx->name);
138+
return 0;
139+
}
140+
141+
if (i2s_dev_rx != i2s_dev_tx && !device_is_ready(i2s_dev_tx)) {
142+
printk("[DSP] %s is not ready\n", i2s_dev_tx->name);
143+
return 0;
144+
}
145+
146+
audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK_CAPTURE;
147+
audio_cfg.dai_type = AUDIO_DAI_TYPE_I2S;
148+
audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH;
149+
audio_cfg.dai_cfg.i2s.channels = 2;
150+
audio_cfg.dai_cfg.i2s.format = I2S_FMT_DATA_FORMAT_I2S;
151+
audio_cfg.dai_cfg.i2s.options = I2S_OPT_FRAME_CLK_MASTER;
152+
audio_cfg.dai_cfg.i2s.frame_clk_freq = SAMPLE_FREQUENCY;
153+
audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab;
154+
audio_cfg.dai_cfg.i2s.block_size = BLOCK_SIZE;
155+
audio_codec_configure(codec_dev, &audio_cfg);
156+
k_msleep(1000);
157+
158+
config.word_size = SAMPLE_BIT_WIDTH;
159+
config.channels = NUMBER_OF_CHANNELS;
160+
config.format = I2S_FMT_DATA_FORMAT_I2S;
161+
config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
162+
config.frame_clk_freq = SAMPLE_FREQUENCY;
163+
config.mem_slab = &mem_slab;
164+
config.block_size = BLOCK_SIZE;
165+
config.timeout = TIMEOUT;
166+
if (!configure_streams(i2s_dev_rx, i2s_dev_tx, &config)) {
167+
return 0;
168+
}
169+
170+
for (;;) {
171+
if (!prepare_transfer(i2s_dev_rx, i2s_dev_tx)) {
172+
return 0;
173+
}
174+
175+
if (!trigger_command(i2s_dev_rx, i2s_dev_tx,
176+
I2S_TRIGGER_START)) {
177+
return 0;
178+
}
179+
180+
printk("[DSP] Streams started.\n");
181+
182+
while (true) {
183+
void *mem_block;
184+
uint32_t block_size;
185+
int ret;
186+
187+
ret = i2s_read(i2s_dev_rx, &mem_block, &block_size);
188+
if (ret < 0) {
189+
printk("[DSP] Failed to read data: %d\n", ret);
190+
break;
191+
}
192+
193+
ret = i2s_write(i2s_dev_tx, mem_block, block_size);
194+
if (ret < 0) {
195+
printk("[DSP] Failed to write data: %d\n", ret);
196+
break;
197+
}
198+
}
199+
200+
printk("[DSP] Streams erroneously stopped.\n");
201+
}
202+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
sample:
2+
name: i.MX RTxxx AMP audio loopback sample
3+
description:
4+
Audio loopback application using the i.MX RTxxx devices as AMP systems.
5+
common:
6+
sysbuild: true
7+
min_ram: 1024
8+
min_flash: 1024
9+
platform_allow:
10+
- mimxrt685_evk/mimxrt685s/cm33
11+
harness: console
12+
harness_config:
13+
type: one_line
14+
regex:
15+
- "Hello World! (.*)(hifi.)"
16+
tests:
17+
sample.nxp.adsp.amp_audio_loopback:
18+
tags: tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
9+
#include "adsp.h"
10+
11+
int main(void)
12+
{
13+
printk("Hello World! %s\n", CONFIG_BOARD_TARGET);
14+
15+
printk("[ARM] Starting DSP...\n");
16+
dsp_start();
17+
18+
return 0;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
include("${CMAKE_CURRENT_LIST_DIR}/../common/remote-adsp-board-select.cmake")
5+
6+
ExternalZephyrProject_Add(
7+
APPLICATION remote
8+
SOURCE_DIR ${APP_DIR}/remote
9+
BOARD ${REMOTE_BOARD}
10+
BUILD_ONLY TRUE
11+
)
12+
13+
add_dependencies(${DEFAULT_IMAGE} remote)
14+
sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} remote)

0 commit comments

Comments
 (0)