Stereo PDM microphones (2 mics) using PDM2PCM middleware - code example?
Hello, i would like to know how to use your PDM2PCM middleware for 2 microphones processing data, if you have some examples for it - it would be perfect.
I was able to get the good sound for mono(with 1 mic) when i get the board for stereo sound, i can not get the proper sound signal.
Microphones are connected using i2s peripheral.
I'm using my custom board with 2 IMP34DT05TR PDM MEMs microphones.
Also it is interesting how TIMer code for stereo microphone should look (when should i start the timer and in which mode ?)
MCU: STM32F412CGU6
Micros: IMP34DT05TR
void MX_I2S3_Init(void)
{
/* USER CODE BEGIN I2S3_Init 0 */
/* USER CODE END I2S3_Init 0 */
/* USER CODE BEGIN I2S3_Init 1 */
/* USER CODE END I2S3_Init 1 */
hi2s3.Instance = SPI3;
hi2s3.Init.Mode = I2S_MODE_MASTER_RX;
hi2s3.Init.Standard = I2S_STANDARD_LSB;
hi2s3.Init.DataFormat = I2S_DATAFORMAT_32B;
hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_44K; // tried all of the audio freq's
hi2s3.Init.CPOL = I2S_CPOL_LOW;
hi2s3.Init.ClockSource = I2S_CLOCK_PLLR;
hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;
if (HAL_I2S_Init(&hi2s3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2S3_Init 2 */
/* USER CODE END I2S3_Init 2 */
}
#include <stdio.h>
#include <string.h>
#include "stm32f4xx_hal.h"
#include "pdm2pcm.h"
#include "serial.h"
// Func macros for serial port logging new line and simple one
#define LOGLN(val) serial_println(console, val)
#define LOG(val) serial_print(console, val)
/**
* Note: if the decimation factor or number of output samples
* per conversion is changed, these buffer sizes will
* need to be changed!
*/
#define PCM_BUF_SIZE 48
// For a decimation factor of 64 and 16-bit wordlength ...
#define PDM_BUF_SIZE (PCM_BUF_SIZE * 4)
static I2S_HandleTypeDef *i2s;
// PCM signal buffer
static int16_t pcm[PCM_BUF_SIZE];
// Buffer used to store the raw PDM micro data
static volatile uint16_t rxbufs[2][PDM_BUF_SIZE];
static volatile uint16_t *rxbuf;
static uint32_t sample_count = 0;
static uint16_t audio_buff_size = PDM_BUF_SIZE;
static __IO uint8_t new_data = 0;
extern serial_t *console;
/*
* @brief: Converter function from PDM to PCM signal
* also send the signal to the UART
* @return: Return 0 in case of success
*/
static int convert_audio_to_pcm(void);
int mic_init(void *instance) {
if(!instance) {
LOGLN("Error: I2S instance passed NULL ptr in mic_init()");
return 1;
}
i2s = instance;
MX_PDM2PCM_Init();
return 0;
}
int mic_start_recording(void) {
HAL_StatusTypeDef status = HAL_I2S_Receive_DMA(i2s, rxbufs[0], audio_buff_size);
if (status != HAL_OK) {
LOGLN("Error: Failed to start I2S transmission in mic_start_recording()");
return 1;
}
sample_count = 0;
// HAL_Delay(10);
return 0;
}
int mic_stop_recording(void) {
return HAL_I2S_DMAStop(i2s);
}
void mic_monitor(void) {
if (new_data) {
new_data = 0;
convert_audio_to_pcm();
}
}
static int convert_audio_to_pcm(void) {
int val = 0;
uint32_t rc = 0;
rc = PDM_Filter(&(((uint8_t *)rxbuf)[0]), &(((uint16_t *)pcm)[0]),
&PDM1_filter_handler);
if (rc != 0) {
LOGLN("Error in PDM->PCM conversion first part.");
return 1;
}
rc = PDM_Filter(&(((uint8_t *)rxbuf)[1]), &(((uint16_t *)pcm)[1]),
&PDM2_filter_handler);
if (rc != 0) {
LOGLN("Error in PDM->PCM conversion second part");
return 1;
}
// 2 bytes per sample
size_t len = 2*PCM_BUF_SIZE;
// output the values to UART for forming the .vaw file
serial_print_bytes(console, &(((uint8_t *)pcm)[0]), len);
sample_count += PCM_BUF_SIZE;
memset(pcm, 0, len);
return 0;
}
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
// could be used if needed (half transfer done callback)
}
void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) {
LOGLN("HAL_I2S_ErrorCallback happened on the i2s interface\n");
}
void HAL_I2S_AbortCallback(I2S_HandleTypeDef *hi2s) {
LOGLN("HAL_I2S_AbortCallback happened on the i2s interface\n");
}
void XferM1CpltCallback(I2S_HandleTypeDef *hi2s) {
LOGLN("XferM1CpltCallback happened on the i2s interface\n");
}
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
if (hi2s != i2s) {
return;
}
rxbuf = rxbufs[0];
new_data = 1;
}
My pdm2pcm code:
/* PDM2PCM init function */
void MX_PDM2PCM_Init(void)
{
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/**
*/
PDM1_filter_handler.bit_order = PDM_FILTER_BIT_ORDER_LSB;
PDM1_filter_handler.endianness = PDM_FILTER_ENDIANNESS_BE;
PDM1_filter_handler.high_pass_tap = 2104533974;
PDM1_filter_handler.in_ptr_channels = 2;
PDM1_filter_handler.out_ptr_channels = 2;
PDM_Filter_Init(&PDM1_filter_handler);
PDM1_filter_config.decimation_factor = PDM_FILTER_DEC_FACTOR_64;
PDM1_filter_config.output_samples_number = 48;
PDM1_filter_config.mic_gain = 28;
PDM_Filter_setConfig(&PDM1_filter_handler, &PDM1_filter_config);
PDM2_filter_handler.bit_order = PDM_FILTER_BIT_ORDER_LSB;
PDM2_filter_handler.endianness = PDM_FILTER_ENDIANNESS_BE;
PDM2_filter_handler.high_pass_tap = 2104533974;
PDM2_filter_handler.in_ptr_channels = 2;
PDM2_filter_handler.out_ptr_channels = 2;
PDM_Filter_Init(&PDM2_filter_handler);
PDM2_filter_config.decimation_factor = PDM_FILTER_DEC_FACTOR_64;
PDM2_filter_config.output_samples_number = 48;
PDM2_filter_config.mic_gain = 28;
PDM_Filter_setConfig(&PDM2_filter_handler, &PDM2_filter_config);
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
what i'm doing now - trying to start the timer with such start function.
Clock configurations done according to Interfacing PDM digital microphones using STM32 MCUs and MPUs - Application note.
Timer settings in attachment
Please share your advice or maybe code example for using such PDM stereo micros with your PDM2PCM middleware and CubeMX
