Skip to content

Commit 1518cc8

Browse files
ananglnashif
authored andcommitted
samples: drivers: Add simple application showing how to use DMIC API
Add a very simple application intended to show how to use the Audio DMIC API and also to be an aid in developing drivers to implement this API. Signed-off-by: Andrzej Głąbek <[email protected]>
1 parent 1bf7c39 commit 1518cc8

File tree

7 files changed

+219
-0
lines changed

7 files changed

+219
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(dmic)
7+
8+
target_sources(app PRIVATE src/main.c)

samples/drivers/audio/dmic/README.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.. _dmic_sample:
2+
3+
DMIC Sample
4+
###########
5+
6+
Overview
7+
********
8+
9+
This is a very simple application intended to show how to use the Audio DMIC
10+
API and also to be an aid in developing drivers to implement this API.
11+
It performs two PDM transfers with different configurations (using one channel
12+
and two channels) but does not in any way process the received audio data.
13+
14+
Requirements
15+
************
16+
17+
The device to be used by the sample is specified by defining a devicetree node
18+
label named ``dmic_dev``.
19+
The sample has been tested on :ref:`nrf52840dk_nrf52840` (nrf52840dk_nrf52840)
20+
and :ref:`nrf5340dk_nrf5340` (nrf5340dk_nrf5340_cpuapp), and provides overlay
21+
files for both of these boards.
22+
23+
Building and Running
24+
********************
25+
26+
The code can be found in :zephyr_file:`samples/drivers/audio/dmic`.
27+
28+
To build and flash the application:
29+
30+
.. zephyr-app-commands::
31+
:zephyr-app: samples/drivers/audio/dmic
32+
:board: nrf52840dk_nrf52840
33+
:goals: build flash
34+
:compact:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (c) 2021 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
dmic_dev: &pdm0 {
8+
status = "okay";
9+
clk-pin = <30>;
10+
din-pin = <31>;
11+
clock-source = "PCLK32M_HFXO";
12+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (c) 2021 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
&clock {
8+
hfclkaudio-frequency = <12288000>;
9+
};
10+
11+
dmic_dev: &pdm0 {
12+
status = "okay";
13+
clk-pin = <25>;
14+
din-pin = <26>;
15+
clock-source = "ACLK";
16+
};

samples/drivers/audio/dmic/prj.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CONFIG_AUDIO=y
2+
CONFIG_AUDIO_DMIC=y
3+
4+
CONFIG_LOG=y
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sample:
2+
name: DMIC sample
3+
tests:
4+
sample.drivers.audio.dmic:
5+
tags: DMIC
6+
filter: dt_nodelabel_enabled("dmic_dev")
7+
integration_platforms:
8+
- nrf52840dk_nrf52840
9+
- nrf5340dk_nrf5340_cpuapp

samples/drivers/audio/dmic/src/main.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) 2021 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr.h>
8+
#include <audio/dmic.h>
9+
10+
#include <logging/log.h>
11+
LOG_MODULE_REGISTER(dmic_sample);
12+
13+
#define MAX_SAMPLE_RATE 16000
14+
#define SAMPLE_BIT_WIDTH 16
15+
#define BYTES_PER_SAMPLE sizeof(int16_t)
16+
/* Milliseconds to wait for a block to be read. */
17+
#define READ_TIMEOUT 1000
18+
19+
/* Size of a block for 100 ms of audio data. */
20+
#define BLOCK_SIZE(_sample_rate, _number_of_channels) \
21+
(BYTES_PER_SAMPLE * (_sample_rate / 10) * _number_of_channels)
22+
23+
/* Driver will allocate blocks from this slab to receive audio data into them.
24+
* Application, after getting a given block from the driver and processing its
25+
* data, needs to free that block.
26+
*/
27+
#define MAX_BLOCK_SIZE BLOCK_SIZE(MAX_SAMPLE_RATE, 2)
28+
#define BLOCK_COUNT 4
29+
static K_MEM_SLAB_DEFINE(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
30+
31+
static int do_pdm_transfer(const struct device *dmic_dev,
32+
struct dmic_cfg *cfg,
33+
size_t block_count)
34+
{
35+
int ret;
36+
37+
LOG_INF("PCM output rate: %u, channels: %u",
38+
cfg->streams[0].pcm_rate, cfg->channel.req_num_chan);
39+
40+
ret = dmic_configure(dmic_dev, cfg);
41+
if (ret < 0) {
42+
LOG_ERR("Failed to configure the driver: %d", ret);
43+
return ret;
44+
}
45+
46+
ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
47+
if (ret < 0) {
48+
LOG_ERR("START trigger failed: %d", ret);
49+
return ret;
50+
}
51+
52+
for (int i = 0; i < block_count; ++i) {
53+
void *buffer;
54+
uint32_t size;
55+
int ret;
56+
57+
ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
58+
if (ret < 0) {
59+
LOG_ERR("%d - read failed: %d", i, ret);
60+
return ret;
61+
}
62+
63+
LOG_INF("%d - got buffer %p of %u bytes", i, buffer, size);
64+
65+
k_mem_slab_free(&mem_slab, &buffer);
66+
}
67+
68+
ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
69+
if (ret < 0) {
70+
LOG_ERR("STOP trigger failed: %d", ret);
71+
return ret;
72+
}
73+
74+
return ret;
75+
}
76+
77+
void main(void)
78+
{
79+
const struct device *dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
80+
int ret;
81+
82+
LOG_INF("DMIC sample");
83+
84+
if (!device_is_ready(dmic_dev)) {
85+
LOG_ERR("%s is not ready", dmic_dev->name);
86+
return;
87+
}
88+
89+
struct pcm_stream_cfg stream = {
90+
.pcm_width = SAMPLE_BIT_WIDTH,
91+
.mem_slab = &mem_slab,
92+
};
93+
struct dmic_cfg cfg = {
94+
.io = {
95+
/* These fields can be used to limit the PDM clock
96+
* configurations that the driver is allowed to use
97+
* to those supported by the microphone.
98+
*/
99+
.min_pdm_clk_freq = 1000000,
100+
.max_pdm_clk_freq = 3500000,
101+
.min_pdm_clk_dc = 40,
102+
.max_pdm_clk_dc = 60,
103+
},
104+
.streams = &stream,
105+
.channel = {
106+
.req_num_streams = 1,
107+
},
108+
};
109+
110+
cfg.channel.req_num_chan = 1;
111+
cfg.channel.req_chan_map_lo =
112+
dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
113+
cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
114+
cfg.streams[0].block_size =
115+
BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
116+
117+
ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
118+
if (ret < 0) {
119+
return;
120+
}
121+
122+
cfg.channel.req_num_chan = 2;
123+
cfg.channel.req_chan_map_lo =
124+
dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) |
125+
dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT);
126+
cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
127+
cfg.streams[0].block_size =
128+
BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
129+
130+
ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
131+
if (ret < 0) {
132+
return;
133+
}
134+
135+
LOG_INF("Exiting");
136+
}

0 commit comments

Comments
 (0)