Hi there,
So, this is in a sequence of attempts to read data from a digital microphone SPH0645 using i2s master protcool on nRF5340. The program layout is as follows:

I have written a thread for reading the i2s data that is enabled only after a semaphore is taken. Eventually I want to use this architecture integrated with a few other microcontroller operations. Here is the main.c file:
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
#define SAMPLE_FREQUENCY 16000
#define SAMPLE_BIT_WIDTH 32
#define BYTES_PER_SAMPLE sizeof(int32_t)
#define NUMBER_OF_CHANNELS 1
#define SAMPLES_PER_BLOCK ((SAMPLE_FREQUENCY / 10) * NUMBER_OF_CHANNELS)
#define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
#define BLOCK_COUNT 20
#define RECORD_DURATION_MS 3000
K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);
K_SEM_DEFINE(enable_recording, 0, 1);
K_THREAD_STACK_DEFINE(recording_thread_stack, 4096);
struct k_thread recording_thread_data;
static const struct device *mic;
static bool recording_active = false;
void start_recording() {
if (!recording_active) {
recording_active = true;
LOG_INF("Starting recording");
int ret = i2s_trigger(mic, I2S_DIR_RX, I2S_TRIGGER_START);
if (ret) {
LOG_ERR("Failed to start I2S recording: %d", ret);
recording_active = false;
} else {
LOG_INF("Ready for recording. Press Button when ready.\n");
k_sem_give(&enable_recording);
}
}
}
void stop_recording() {
if (recording_active) {
LOG_INF("Stopping recording");
recording_active = false;
int ret = i2s_trigger(mic, I2S_DIR_RX, I2S_TRIGGER_STOP);
if (ret) {
LOG_ERR("Failed to stop I2S recording: %d", ret);
}
}
}
void mic_worker_thread(void *p1, void *p2, void *p3) {
LOG_INF("Worker thread started");
while (1) {
// Wait for the semaphore to be given
k_sem_take(&enable_recording, K_FOREVER);
start_recording();
void *mem_block;
size_t data_size;
int64_t start_time = k_uptime_get();
while (k_uptime_get() - start_time < RECORD_DURATION_MS) {
data_size = 0;
int ret = i2s_read(mic, &mem_block, &data_size);
if (ret < 0) {
LOG_ERR("Failed to read data: %d", ret);
break;
}
if (data_size > 0) {
LOG_INF("Data size: %zu bytes", data_size);
LOG_INF("Elapsed time: %lld ms", k_uptime_get() - start_time);
// Free the memory block after processing
k_mem_slab_free(&mem_slab, &mem_block);
LOG_DBG("Block of data freed.\n");
}
}
recording_active = false;
stop_recording();
// Semaphore should only be given once the recording session is fully complete
k_sem_give(&enable_recording);
}
}
void recording_init() {
mic = DEVICE_DT_GET(DT_NODELABEL(i2s0));
if (!device_is_ready(mic)) {
LOG_ERR("I2S device not ready");
return;
}
struct i2s_config config = {
.word_size = SAMPLE_BIT_WIDTH,
.channels = NUMBER_OF_CHANNELS,
.format = I2S_FMT_DATA_FORMAT_I2S,
.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER,
.frame_clk_freq = SAMPLE_FREQUENCY,
.mem_slab = &mem_slab,
.block_size = BLOCK_SIZE,
.timeout = 1000,
};
LOG_INF("Configured I2S device");
if (i2s_configure(mic, I2S_DIR_RX, &config) != 0) {
LOG_ERR("Failed to configure I2S");
}
k_thread_create(
&recording_thread_data,
recording_thread_stack,
K_THREAD_STACK_SIZEOF(recording_thread_stack),
mic_worker_thread, // Thread function
NULL, NULL, NULL, // Arguments to the thread
5, 0, K_NO_WAIT // Priority, options, and start time
);
}
int main(void) {
LOG_INF("Starting main thread");
recording_init();
// while (1) {
k_sem_give(&enable_recording);
// start_recording();
k_sleep(K_SECONDS(5));
// }
// k_sem_take(&enable_recording, K_FOREVER);
return 0;
}
Here is the overlay file to point out pin connections:
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
&clock {
// hfclk-source = "HFXO"; /* Select the High-Frequency External Oscillator */
status = "okay";
};
&pinctrl {
i2s0_default_alt: i2s0_default_alt {
group1 {
psels = <NRF_PSEL(I2S_SCK_M, 0, 26)>,
<NRF_PSEL(I2S_LRCK_M, 0, 7)>,
<NRF_PSEL(I2S_SDOUT, 1, 13)>,
<NRF_PSEL(I2S_SDIN, 0, 25)>;
};
};
};
&clock {
hfclkaudio-frequency = <11289600>;
};
i2s_rxtx: &i2s0 {
status = "okay";
pinctrl-0 = <&i2s0_default_alt>;
pinctrl-names = "default";
clock-source = "ACLK";
};
Here are my configuration settings for the project:
# CONFIG_STDOUT_CONSOLE=y CONFIG_PRINTK=y CONFIG_PWM=y CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_I2S=y CONFIG_GPIO=y CONFIG_I2S_NRFX_RX_BLOCK_COUNT=10 # CONFIG_LOG_TIMESTAMP=n CONFIG_LOG=y # CONFIG_LOG_DEFAULT_LEVEL=4 CONFIG_LOG_PRINTK=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_PWM_LOG_LEVEL_DBG=y CONFIG_LOG_BUFFER_SIZE=4096 CONFIG_LOG_PROCESS_THREAD=y CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=4096 # CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP=n
But as I run the application, I see a hard fault occurring after four samples are received:
[00:00:00.266,723] <27>[0m<inf> main: Configured I2S device<27>[0m<\r><\n> [00:00:00.272,125] <27>[0m<inf> i2s_nrfx: I2S MCK frequency: 1026327, actual PCM rate: 16036<27>[0m<\r><\n> [00:00:00.280,334] <27>[0m<inf> main: Worker thread started<27>[0m<\r><\n> [00:00:00.285,675] <27>[0m<inf> main: Starting recording<27>[0m<\r><\n> [00:[00:00:00.291,168] <27>[0m<inf> i2s_nrfx: Next buffers: 0/0x2001ee98<27>[0m<\r><\n> 00:00.290,802] <27>[0m<inf> main: Ready for recording. Press Button when ready.<\n><27>[0m<\r><\n> [00:00:00.390,960] <27>[0m<inf> i2s_nrfx: Queued RX 0x20020798<27>[0m<\r><\n> [00:00:00.396,514] <27>[0m<inf> i2s_nrfx: Next buffers: 0/0x2001d598<27>[0m<\r><\n> [00:00:00.402,648] <27>[0m<inf> i2s_nrfx: Released RX 0x20020798<27>[0m<\r><\n> [00:00:00.408,416] <27>[0m<inf> main: Data size: 6400 bytes<27>[0m<\r><\n> [00:00:00.413,787] <27>[0m<inf> main: Elapsed time: 109 ms<27>[0m<\r><\n> [00:00:00.490,722] <27>[0m<inf> i2s_nrfx: Queued RX 0x2001ee98<27>[0m<\r><\n> [00:00:00.496,276] <27>[0m<inf> i2s_nrfx: Next buffers: 0/0x20001f18<27>[0m<\r><\n> [00:00:00.502,410] <27>[0m<inf> i2s_nrfx: Released RX 0x2001ee98<27>[0m<\r><\n> [00:00:00.508,209] <27>[0m<inf> main: Data size: 6400 bytes<27>[0m<\r><\n> [00:00:00.513,580] <27>[0m<inf> main: Elapsed time: 209 ms<27>[0m<\r><\n> [00:00:00.590,484] <27>[0m<inf> i2s_nrfx: Queued RX 0x2001d598<27>[0m<\r><\n> [00:00:00.596,069] <27>[0m<inf> i2s_nrfx: Next buffers: 0/0x20001f18<27>[0m<\r><\n> [00:00:00.602,203] <27>[0m<inf> i2s_nrfx: Released RX 0x2001d598<27>[0m<\r><\n> [00:00:00.607,971] <27>[0m<inf> main: Data size: 6400 bytes<27>[0m<\r><\n> [00:00:00.613,342] <27>[0m<inf> main: Elapsed time: 309 ms<27>[0m<\r><\n> [00:00:00.690,277] <27>[0m<inf> i2s_nrfx: Queued RX 0x20001f18<27>[0m<\r><\n> [00:00:00.695,831] <27>[0m<inf> i2s_nrfx: Next buffers: 0/0x20001f18<27>[0m<\r><\n> [00:00:00.701,965] <27>[0m<inf> i2s_nrfx: Released RX 0x20001f18<27>[0m<\r><\n> [00:00:00.707,763] <27>[0m<inf> main: Data size: 6400 bytes<27>[0m<\r><\n> [00:00:00.713,104] <27>[0m<inf> main: Elapsed time: 409 ms<27>[0m<\r><\n> [00:00:00.718,414] <27>[1;31m<err> os: [00:00:00.721,496] <27>[1;31m<err> os: ***** HARD FAULT *****<27>[0m<\r><\n> [00:00:00.727,020] <27>[1;31m<err> os: Fault escalation (see below)<27>[0m<\r><\n> [00:00:00.733,245] <27>[1;31m<err> os: ***** MPU FAULT *****<27>[0m<\r><\n> [00:00:00.738,708] <27>[1;31m<err> os: Instruction Access Violation<27>[0m<\r><\n> [00:00:00.744,934] <27>[1;31m<err> os: r0/a1: 0x200025a0 r1/a2: 0xfb620000 r2/a3: 0x80000000<27>[0m<\r><\n> [00:00:00.753,570] <27>[1;31m<err> os: r3/a4: 0x00000002 r12/ip: 0x00002425 r14/lr: 0x00002453<27>[0m<\r><\n> [00:00:00.762,207] <27>[1;31m<err> os: xpsr: 0x41000004<27>[0m<\r><\n> [00:00:00.767,395] <27>[1;31m<err> os: Faulting instruction address (r15/pc): 0x000071d0<27>[0m<\r><\n> [00:00:00.775,268] <27>[1;31m<err> os: >>> ZEPHYR FATAL ERROR 20: Unknown error on CPU 0<27>[0m<\r><\n> [00:00:00.783,142] <27>[1;31m<err> os: Fault during interrupt handling<\n><27>[0m<\r><\n> [00:00:00.789,520] <27>[1;31m<err> os: Current thread: 0x200003a0 (unknown)<27>[0m<\r><\n> [00:00:00.796,264] <27>[1;31m<err> os: Halting system<27>[0m
I have not been able to trace back the instruction from the provided address: 0x000071d0. The command 'addrline.exe' gives me '????'. I am freeing the memory as soon as the i2s_read happens.
I have tried extending the thread call stack but to no avail.
Please advise what can be done.