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 <andrzej.glabek@nordicsemi.no>
This commit is contained in:
parent
1bf7c391b8
commit
1518cc8337
7 changed files with 219 additions and 0 deletions
8
samples/drivers/audio/dmic/CMakeLists.txt
Normal file
8
samples/drivers/audio/dmic/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(dmic)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
34
samples/drivers/audio/dmic/README.rst
Normal file
34
samples/drivers/audio/dmic/README.rst
Normal file
|
@ -0,0 +1,34 @@
|
|||
.. _dmic_sample:
|
||||
|
||||
DMIC Sample
|
||||
###########
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This is 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.
|
||||
It performs two PDM transfers with different configurations (using one channel
|
||||
and two channels) but does not in any way process the received audio data.
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
The device to be used by the sample is specified by defining a devicetree node
|
||||
label named ``dmic_dev``.
|
||||
The sample has been tested on :ref:`nrf52840dk_nrf52840` (nrf52840dk_nrf52840)
|
||||
and :ref:`nrf5340dk_nrf5340` (nrf5340dk_nrf5340_cpuapp), and provides overlay
|
||||
files for both of these boards.
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
The code can be found in :zephyr_file:`samples/drivers/audio/dmic`.
|
||||
|
||||
To build and flash the application:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/drivers/audio/dmic
|
||||
:board: nrf52840dk_nrf52840
|
||||
:goals: build flash
|
||||
:compact:
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
dmic_dev: &pdm0 {
|
||||
status = "okay";
|
||||
clk-pin = <30>;
|
||||
din-pin = <31>;
|
||||
clock-source = "PCLK32M_HFXO";
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&clock {
|
||||
hfclkaudio-frequency = <12288000>;
|
||||
};
|
||||
|
||||
dmic_dev: &pdm0 {
|
||||
status = "okay";
|
||||
clk-pin = <25>;
|
||||
din-pin = <26>;
|
||||
clock-source = "ACLK";
|
||||
};
|
4
samples/drivers/audio/dmic/prj.conf
Normal file
4
samples/drivers/audio/dmic/prj.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_AUDIO=y
|
||||
CONFIG_AUDIO_DMIC=y
|
||||
|
||||
CONFIG_LOG=y
|
9
samples/drivers/audio/dmic/sample.yaml
Normal file
9
samples/drivers/audio/dmic/sample.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
sample:
|
||||
name: DMIC sample
|
||||
tests:
|
||||
sample.drivers.audio.dmic:
|
||||
tags: DMIC
|
||||
filter: dt_nodelabel_enabled("dmic_dev")
|
||||
integration_platforms:
|
||||
- nrf52840dk_nrf52840
|
||||
- nrf5340dk_nrf5340_cpuapp
|
136
samples/drivers/audio/dmic/src/main.c
Normal file
136
samples/drivers/audio/dmic/src/main.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <audio/dmic.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(dmic_sample);
|
||||
|
||||
#define MAX_SAMPLE_RATE 16000
|
||||
#define SAMPLE_BIT_WIDTH 16
|
||||
#define BYTES_PER_SAMPLE sizeof(int16_t)
|
||||
/* Milliseconds to wait for a block to be read. */
|
||||
#define READ_TIMEOUT 1000
|
||||
|
||||
/* Size of a block for 100 ms of audio data. */
|
||||
#define BLOCK_SIZE(_sample_rate, _number_of_channels) \
|
||||
(BYTES_PER_SAMPLE * (_sample_rate / 10) * _number_of_channels)
|
||||
|
||||
/* Driver will allocate blocks from this slab to receive audio data into them.
|
||||
* Application, after getting a given block from the driver and processing its
|
||||
* data, needs to free that block.
|
||||
*/
|
||||
#define MAX_BLOCK_SIZE BLOCK_SIZE(MAX_SAMPLE_RATE, 2)
|
||||
#define BLOCK_COUNT 4
|
||||
static K_MEM_SLAB_DEFINE(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
|
||||
|
||||
static int do_pdm_transfer(const struct device *dmic_dev,
|
||||
struct dmic_cfg *cfg,
|
||||
size_t block_count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOG_INF("PCM output rate: %u, channels: %u",
|
||||
cfg->streams[0].pcm_rate, cfg->channel.req_num_chan);
|
||||
|
||||
ret = dmic_configure(dmic_dev, cfg);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure the driver: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("START trigger failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < block_count; ++i) {
|
||||
void *buffer;
|
||||
uint32_t size;
|
||||
int ret;
|
||||
|
||||
ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("%d - read failed: %d", i, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("%d - got buffer %p of %u bytes", i, buffer, size);
|
||||
|
||||
k_mem_slab_free(&mem_slab, &buffer);
|
||||
}
|
||||
|
||||
ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("STOP trigger failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
const struct device *dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
|
||||
int ret;
|
||||
|
||||
LOG_INF("DMIC sample");
|
||||
|
||||
if (!device_is_ready(dmic_dev)) {
|
||||
LOG_ERR("%s is not ready", dmic_dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pcm_stream_cfg stream = {
|
||||
.pcm_width = SAMPLE_BIT_WIDTH,
|
||||
.mem_slab = &mem_slab,
|
||||
};
|
||||
struct dmic_cfg cfg = {
|
||||
.io = {
|
||||
/* These fields can be used to limit the PDM clock
|
||||
* configurations that the driver is allowed to use
|
||||
* to those supported by the microphone.
|
||||
*/
|
||||
.min_pdm_clk_freq = 1000000,
|
||||
.max_pdm_clk_freq = 3500000,
|
||||
.min_pdm_clk_dc = 40,
|
||||
.max_pdm_clk_dc = 60,
|
||||
},
|
||||
.streams = &stream,
|
||||
.channel = {
|
||||
.req_num_streams = 1,
|
||||
},
|
||||
};
|
||||
|
||||
cfg.channel.req_num_chan = 1;
|
||||
cfg.channel.req_chan_map_lo =
|
||||
dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
|
||||
cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
|
||||
cfg.streams[0].block_size =
|
||||
BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
|
||||
|
||||
ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cfg.channel.req_num_chan = 2;
|
||||
cfg.channel.req_chan_map_lo =
|
||||
dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) |
|
||||
dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT);
|
||||
cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
|
||||
cfg.streams[0].block_size =
|
||||
BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
|
||||
|
||||
ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INF("Exiting");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue