Skip to content

Commit 8b7fb86

Browse files
committed
tests: drivers: audio: Add test that collects audio from PDM microphone
Verify operation of PDM driver with physical microphone and manual sound analysis. Signed-off-by: Sebastian Głąb <sebastian.glab@nordicsemi.no>
1 parent b4b0ece commit 8b7fb86

9 files changed

+260
-0
lines changed

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@
838838
/tests/bluetooth/bsim/nrf_auraconfig/ @nrfconnect/ncs-audio
839839
/tests/bluetooth/tester/ @carlescufi @nrfconnect/ncs-paladin
840840
/tests/crypto/ @stephen-nordic @magnev
841+
/tests/drivers/audio/dmic_dump_buffer/ @nrfconnect/ncs-low-level-test
841842
/tests/drivers/audio/pdm_loopback/ @nrfconnect/ncs-low-level-test
842843
/tests/drivers/gpio/ @nrfconnect/ncs-low-level-test @nrfconnect/ncs-ll-ursus
843844
/tests/drivers/flash/flash_ipuc/ @nrfconnect/ncs-charon
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(dmic)
7+
8+
target_sources(app PRIVATE src/main.c)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
This test uses DMIC driver to collect sound from PDM microphone.
2+
Audio samples are output on serial port @921600 bit/s in binary mode.
3+
4+
5+
Follow these steps to collect and analyse sound:
6+
7+
1. Connect PDM microphone (tested with https://www.adafruit.com/product/3492) to PDM_CLK and PDM_DIN as defined in the board overlay.
8+
9+
2. Compile and run dmic_dump_buffer test:
10+
west build -b nrf54l15dk/nrf54l15/cpuapp --pristine --test-item drivers.audio.dmic_dump_buffer .
11+
west flash --erase
12+
13+
3. Store output from serial port to a file:
14+
- press RESET button on DK to stop execution
15+
- start data capture, f.e.
16+
picocom -f n -b 921600 /dev/serial/by-id/usb-SEGGER_J-Link_00105xxx-if02 > /home/user/sound_capture.raw
17+
- release RESET button
18+
19+
4. Collect sound with the microphone. Then, stop data acquisition (f.e. Ctr+a, Ctrl+x)
20+
21+
5. If using picocom, remove text at the beginning and at the end of the file (that is added by picocom).
22+
23+
6. Convert end line symbols
24+
dos2unix -f /home/user/sound_capture.raw
25+
26+
7. Import raw data to Audacity (Signed 16-bit PCM; little-endian; mono; 16000Hz).
27+
28+
This test is based on https://docs.zephyrproject.org/latest/samples/shields/x_nucleo_iks02a1/microphone/README.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
&pinctrl {
8+
pdm0_default_alt: pdm0_default_alt {
9+
group1 {
10+
psels = <NRF_PSEL(PDM_CLK, 0, 30)>,
11+
<NRF_PSEL(PDM_DIN, 0, 31)>;
12+
};
13+
};
14+
};
15+
16+
dmic_dev: &pdm0 {
17+
status = "okay";
18+
pinctrl-0 = <&pdm0_default_alt>;
19+
pinctrl-names = "default";
20+
clock-source = "PCLK32M_HFXO";
21+
};
22+
23+
&uart0 {
24+
current-speed = < 921600 >;
25+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
&clock {
8+
hfclkaudio-frequency = <12288000>;
9+
};
10+
11+
&pinctrl {
12+
pdm0_default_alt: pdm0_default_alt {
13+
group1 {
14+
psels = <NRF_PSEL(PDM_CLK, 0, 25)>,
15+
<NRF_PSEL(PDM_DIN, 0, 26)>;
16+
};
17+
};
18+
};
19+
20+
dmic_dev: &pdm0 {
21+
status = "okay";
22+
pinctrl-0 = <&pdm0_default_alt>;
23+
pinctrl-names = "default";
24+
clock-source = "ACLK";
25+
};
26+
27+
&uart0 {
28+
current-speed = < 921600 >;
29+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
&pinctrl {
8+
pdm20_default_alt: pdm20_default_alt {
9+
group1 {
10+
psels = <NRF_PSEL(PDM_CLK, 1, 12)>,
11+
<NRF_PSEL(PDM_DIN, 1, 13)>;
12+
};
13+
};
14+
};
15+
16+
dmic_dev: &pdm20 {
17+
status = "okay";
18+
pinctrl-0 = <&pdm20_default_alt>;
19+
pinctrl-names = "default";
20+
clock-source = "PCLK32M";
21+
};
22+
23+
&uart20 {
24+
current-speed = < 921600 >;
25+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CONFIG_BOOT_BANNER=n
2+
CONFIG_NCS_BOOT_BANNER=n
3+
4+
CONFIG_AUDIO=y
5+
CONFIG_AUDIO_DMIC=y
6+
7+
CONFIG_LOG=n
8+
CONFIG_LOG_MODE_IMMEDIATE=n
9+
CONFIG_PRINTK=y
10+
11+
CONFIG_MAIN_STACK_SIZE=16384
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <string.h>
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/audio/dmic.h>
10+
11+
#include <zephyr/logging/log.h>
12+
LOG_MODULE_REGISTER(dmic_sample);
13+
14+
#define SAMPLE_RATE 16000
15+
#define SAMPLE_BIT_WIDTH 16
16+
#define BYTES_PER_SAMPLE (SAMPLE_BIT_WIDTH / 8)
17+
#define NO_OF_CHANNELS 1
18+
19+
/* Milliseconds to wait for a block to be captured by PCM peripheral. */
20+
#define READ_TIMEOUT 1200
21+
22+
/* Driver will allocate blocks from this slab to receive audio data into them.
23+
* Application, after getting a given block from the driver and processing its
24+
* data, needs to free that block.
25+
*/
26+
#define AUDIO_BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLE_RATE * NO_OF_CHANNELS / 10)
27+
/* Driver allocates memory "in advance" therefore 2 blocks may be not enough. */
28+
#define BLOCK_COUNT 4
29+
K_MEM_SLAB_DEFINE_STATIC(mem_slab, AUDIO_BLOCK_SIZE, BLOCK_COUNT, 4);
30+
31+
int main(void)
32+
{
33+
const struct device *const dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
34+
int ret;
35+
int loop_counter = 1;
36+
void *buffer;
37+
uint32_t size;
38+
39+
if (!device_is_ready(dmic_dev)) {
40+
LOG_ERR("%s is not ready", dmic_dev->name);
41+
return 0;
42+
}
43+
44+
struct pcm_stream_cfg stream = {
45+
.pcm_rate = SAMPLE_RATE,
46+
.pcm_width = SAMPLE_BIT_WIDTH,
47+
.block_size = AUDIO_BLOCK_SIZE,
48+
.mem_slab = &mem_slab,
49+
};
50+
51+
struct dmic_cfg cfg = {
52+
.io = {
53+
/* These fields can be used to limit the PDM clock
54+
* configurations that the driver is allowed to use
55+
* to those supported by the microphone.
56+
*/
57+
.min_pdm_clk_freq = 1000000,
58+
.max_pdm_clk_freq = 3250000,
59+
.min_pdm_clk_dc = 40,
60+
.max_pdm_clk_dc = 60,
61+
},
62+
.streams = &stream,
63+
.channel = {
64+
.req_num_chan = 1,
65+
.req_num_streams = 1,
66+
.req_chan_map_lo = dmic_build_channel_map(0, 0, PDM_CHAN_LEFT),
67+
},
68+
};
69+
70+
ret = dmic_configure(dmic_dev, &cfg);
71+
if (ret < 0) {
72+
LOG_ERR("Failed to configure the driver: %d", ret);
73+
return ret;
74+
}
75+
76+
ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
77+
if (ret < 0) {
78+
LOG_ERR("START trigger failed: %d", ret);
79+
return ret;
80+
}
81+
82+
while (1) {
83+
ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
84+
if (ret < 0) {
85+
LOG_ERR("%d - read failed: %d", loop_counter, ret);
86+
return ret;
87+
}
88+
89+
/* Print buffer on serial port (in binary mode). */
90+
unsigned char pcm_l, pcm_h;
91+
int j;
92+
93+
uint16_t *pcm_out = buffer;
94+
95+
for (j = 0; j < size/2; j++) {
96+
pcm_l = (char)(pcm_out[j] & 0xFF);
97+
pcm_h = (char)((pcm_out[j] >> 8) & 0xFF);
98+
99+
z_impl_k_str_out(&pcm_l, 1);
100+
z_impl_k_str_out(&pcm_h, 1);
101+
}
102+
103+
k_mem_slab_free(&mem_slab, buffer);
104+
105+
loop_counter++;
106+
}
107+
108+
/* Dead code; left for reference. */
109+
ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
110+
if (ret < 0) {
111+
LOG_ERR("STOP trigger failed: %d", ret);
112+
return ret;
113+
}
114+
115+
return 0;
116+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
common:
2+
build_only: true
3+
tags:
4+
- drivers
5+
- dmic
6+
- ci_tests_drivers_audio
7+
harness: console
8+
harness_config:
9+
fixture: physical_microphone
10+
11+
tests:
12+
drivers.audio.dmic_dump_buffer:
13+
filter: dt_nodelabel_enabled("dmic_dev")
14+
platform_allow:
15+
- nrf52840dk/nrf52840
16+
- nrf5340dk/nrf5340/cpuapp
17+
- nrf54l15dk/nrf54l15/cpuapp

0 commit comments

Comments
 (0)