Hello, we are capturing sound with a PDM mic, and sending it to a codec through I2S. We have tested the I2S with software generated pure tones, and it is working properly. When we send the mic sound to the coded it is distorted so we think the problem is related to the microphone missconfiguration.
There are two interrupts, one for I2S, another for the PDM. We are using nordic drivers for both. The PDM buffer is copied in a "for loop" into the I2S when both interrup handlers mark the buffer release event.
The microphone is configured for data capture on clk rise, mono. Desired sampling is 16KHz.
Thanks in advance for reviewing the code.
#include "pdm-microphone.h"
#include "I2S_port.h"
#include <nrfx_pdm.h>
#include <nrfx.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(PDMport);
//Definir el tipo del array igual que word_size
int16_t pdm_data_frame[NUM_SAMPLES];
int16_t pdm_data_frame2[NUM_SAMPLES];
int16_t *pdm_active_buffer = pdm_data_frame;
int16_t *pdm_previous_buffer = pdm_data_frame2;
bool pdm_ready_flag = false;
//uint16_t pdm_buffer_size = PDM_N_WORDS;
uint16_t pdm_buffer_size = NUM_SAMPLES;
ISR_DIRECT_DECLARE(pdm_isr_handler)
{
nrfx_pdm_irq_handler();
ISR_DIRECT_PM(); // PM done after servicing interrupt for best latency
return 1;
}
static void pdm_data_handler(nrfx_pdm_evt_t const * p_evt)
{
nrfx_err_t err = 0;
LOG_INF("PDM data Handler");
if(true == p_evt->buffer_requested){
err = nrfx_pdm_buffer_set(pdm_active_buffer, pdm_buffer_size);
if(err != NRFX_SUCCESS)
{
printk("PDM buffer init error: %d\n", err);
}
}
if(p_evt->buffer_released != 0){
// Swap active and next buffer
uint32_t *pdm_tmp = pdm_active_buffer;
pdm_active_buffer = pdm_previous_buffer;
pdm_previous_buffer = pdm_tmp;
pdm_ready_flag = true;
LOG_INF("PDM buffer released, dataflag =TRUE");
}
}
void init_microphone ()
{
nrfx_pdm_config_t config_pdm = NRFX_PDM_DEFAULT_CONFIG(PDM_CLK_PIN, PDM_DIN_PIN);
//***Run from 32MHz
//config_pdm.clock_freq = NRF_PDM_FREQ_1280K;
//config_pdm.ratio = NRF_PDM_RATIO_80X;
//***Run from ACLK, PDM_CLK =1.024MHz (fsample= PDM_CLK/Ratio = 16KHz)
//***PDM_CLK= fsource / [(4096**1048576)/(PDMCLKCTRL_regval)];, fsample= PDM_CLK / ratio.
config_pdm.clock_freq = 0x15555555;
config_pdm.mclksrc = NRF_PDM_MCLKSRC_ACLK;
//Select-->GND , MIC captura dato en flanco de subida.
config_pdm.edge = NRF_PDM_EDGE_LEFTRISING;
IRQ_DIRECT_CONNECT (PDM0_IRQn, 0, pdm_isr_handler, 0);
nrfx_err_t err = nrfx_pdm_init(&config_pdm, pdm_data_handler);
if(err != NRFX_SUCCESS){
printk("PDM init error: %d\n", err);
}
err = nrfx_pdm_start();
if (err == NRFX_SUCCESS)
{
printk("Pdm start was successfull\n");
}
else {
printk("Pdm start was NOT successfull\n");
}
}
this is the main code:
int main(void)
{
nrfx_err_t err_code;
err_code = get_sound_init();
//***Configura I2C
init_i2c_device();
//***Configura microphono PDM
init_microphone();
while (true) {
if (I2S_ready_flag)
{
if (pdm_ready_flag)
{
convert_PDM_buffer_to_I2S_output();
// Reset the data_ready_flag
data_ready_flag = false;
pdm_ready_flag = false;
}
}
k_msleep(10);
}
return 0;
}