Merge branch 'fix/example_pdm_mic_recording' into 'master'

example: Fixed example I2S PDM microphone recording on sdcard

Closes IDF-3952 and IDFGH-5912

See merge request espressif/esp-idf!14928
This commit is contained in:
Kevin (Lao Kaiyao)
2021-10-08 06:25:31 +00:00
10 changed files with 224 additions and 157 deletions

View File

@@ -1550,10 +1550,10 @@ static esp_err_t i2s_check_cfg_validity(i2s_port_t i2s_num, i2s_hal_config_t *cf
if (cfg->mode & I2S_MODE_PDM) { if (cfg->mode & I2S_MODE_PDM) {
ESP_RETURN_ON_FALSE(i2s_num == I2S_NUM_0, ESP_ERR_INVALID_ARG, TAG, "I2S PDM mode only support on I2S0"); ESP_RETURN_ON_FALSE(i2s_num == I2S_NUM_0, ESP_ERR_INVALID_ARG, TAG, "I2S PDM mode only support on I2S0");
#if !SOC_I2S_SUPPORTS_PDM_TX #if !SOC_I2S_SUPPORTS_PDM_TX
ESP_RETURN_ON_FALSE(cfg->mode & I2S_MODE_TX, ESP_ERR_INVALID_ARG, TAG, "PDM does not support TX on this chip"); ESP_RETURN_ON_FALSE(!(cfg->mode & I2S_MODE_TX), ESP_ERR_INVALID_ARG, TAG, "PDM does not support TX on this chip");
#endif // SOC_I2S_SUPPORTS_PDM_TX #endif // SOC_I2S_SUPPORTS_PDM_TX
#if !SOC_I2S_SUPPORTS_PDM_RX #if !SOC_I2S_SUPPORTS_PDM_RX
ESP_RETURN_ON_FALSE(cfg->mode & I2S_MODE_RX, ESP_ERR_INVALID_ARG, TAG, "PDM does not support RX on this chip"); ESP_RETURN_ON_FALSE(!(cfg->mode & I2S_MODE_RX), ESP_ERR_INVALID_ARG, TAG, "PDM does not support RX on this chip");
#endif // SOC_I2S_SUPPORTS_PDM_RX #endif // SOC_I2S_SUPPORTS_PDM_RX
} }
#else #else

View File

@@ -1,16 +1,8 @@
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for I2S register operations // The LL layer for I2S register operations
/******************************************************************************* /*******************************************************************************
@@ -86,6 +78,26 @@ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw)
hw->rx_clkm_conf.rx_clk_active = 1; hw->rx_clkm_conf.rx_clk_active = 1;
} }
/**
* @brief Disable I2S tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.tx_clk_active = 0;
}
/**
* @brief Disable I2S rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw)
{
hw->rx_clkm_conf.rx_clk_active = 0;
}
/** /**
* @brief I2S mclk use tx module clock * @brief I2S mclk use tx module clock
* *

View File

@@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/******************************************************************************* /*******************************************************************************
* NOTICE * NOTICE
@@ -87,6 +79,26 @@ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw)
hw->rx_clkm_conf.rx_clk_active = 1; hw->rx_clkm_conf.rx_clk_active = 1;
} }
/**
* @brief Disable I2S tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.tx_clk_active = 0;
}
/**
* @brief Disable I2S rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw)
{
hw->rx_clkm_conf.rx_clk_active = 0;
}
/** /**
* @brief I2S mclk use tx module clock * @brief I2S mclk use tx module clock
* *

View File

@@ -1,16 +1,8 @@
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for I2S register operations // The LL layer for I2S register operations
/******************************************************************************* /*******************************************************************************
@@ -87,6 +79,26 @@ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw)
hw->rx_clkm_conf.rx_clk_active = 1; hw->rx_clkm_conf.rx_clk_active = 1;
} }
/**
* @brief Disable I2S tx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.tx_clk_active = 0;
}
/**
* @brief Disable I2S rx module clock
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw)
{
hw->rx_clkm_conf.rx_clk_active = 0;
}
/** /**
* @brief I2S mclk use tx module clock * @brief I2S mclk use tx module clock
* *

View File

@@ -1,16 +1,8 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The HAL layer for I2S (common part) // The HAL layer for I2S (common part)
@@ -104,6 +96,15 @@ void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rat
{ {
/* enable pdm tx mode */ /* enable pdm tx mode */
i2s_ll_tx_enable_pdm(hal->dev, true); i2s_ll_tx_enable_pdm(hal->dev, true);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_tx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_tx_clk(hal->dev);
/* Still need to enable the first 2 TDM channel mask to get the correct number of frame */
i2s_ll_tx_set_active_chan_mask(hal->dev, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1);
#else
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
#endif
/* set pdm tx default presacle */ /* set pdm tx default presacle */
i2s_ll_tx_set_pdm_prescale(hal->dev, 0); i2s_ll_tx_set_pdm_prescale(hal->dev, 0);
/* set pdm tx default sacle of high pass filter */ /* set pdm tx default sacle of high pass filter */
@@ -140,6 +141,18 @@ void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal)
i2s_ll_rx_enable_pdm(hal->dev, true); i2s_ll_rx_enable_pdm(hal->dev, true);
/* set pdm rx downsample number */ /* set pdm rx downsample number */
i2s_ll_rx_set_pdm_dsr(hal->dev, I2S_PDM_DSR_8S); i2s_ll_rx_set_pdm_dsr(hal->dev, I2S_PDM_DSR_8S);
#if !SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
#endif
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_rx_clk(hal->dev);
/* Still need to enable the first 2 TDM channel mask to get the correct number of frame */
i2s_ll_rx_set_active_chan_mask(hal->dev, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1);
#else
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
#endif
} }
#endif // SOC_I2S_SUPPORTS_PDM_RX #endif // SOC_I2S_SUPPORTS_PDM_RX
@@ -286,8 +299,8 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
{ {
/* Set tx common mode */ /* Set tx common mode */
i2s_hal_tx_set_common_mode(hal, hal_cfg); i2s_hal_tx_set_common_mode(hal, hal_cfg);
i2s_hal_tx_set_channel_style(hal, hal_cfg);
} }
i2s_hal_tx_set_channel_style(hal, hal_cfg);
} }
/* Set configurations for RX mode */ /* Set configurations for RX mode */
@@ -304,8 +317,8 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
{ {
/* Set rx common mode */ /* Set rx common mode */
i2s_hal_rx_set_common_mode(hal, hal_cfg); i2s_hal_rx_set_common_mode(hal, hal_cfg);
i2s_hal_rx_set_channel_style(hal, hal_cfg);
} }
i2s_hal_rx_set_channel_style(hal, hal_cfg);
} }
/* Set configurations for full-duplex mode */ /* Set configurations for full-duplex mode */
@@ -318,3 +331,35 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf
} }
} }
} }
void i2s_hal_start_tx(i2s_hal_context_t *hal)
{
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_enable_clock(hal->dev);
#endif
i2s_ll_tx_start(hal->dev);
}
void i2s_hal_start_rx(i2s_hal_context_t *hal)
{
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_enable_clock(hal->dev);
#endif
i2s_ll_rx_start(hal->dev);
}
void i2s_hal_stop_tx(i2s_hal_context_t *hal)
{
i2s_ll_tx_stop(hal->dev);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_disable_clock(hal->dev);
#endif
}
void i2s_hal_stop_rx(i2s_hal_context_t *hal)
{
i2s_ll_rx_stop(hal->dev);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_disable_clock(hal->dev);
#endif
}

View File

@@ -1,16 +1,8 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/******************************************************************************* /*******************************************************************************
* NOTICE * NOTICE
@@ -176,28 +168,28 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal);
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
*/ */
#define i2s_hal_start_tx(hal) i2s_ll_tx_start((hal)->dev) void i2s_hal_start_tx(i2s_hal_context_t *hal);
/** /**
* @brief Start I2S rx * @brief Start I2S rx
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
*/ */
#define i2s_hal_start_rx(hal) i2s_ll_rx_start((hal)->dev) void i2s_hal_start_rx(i2s_hal_context_t *hal);
/** /**
* @brief Stop I2S tx * @brief Stop I2S tx
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
*/ */
#define i2s_hal_stop_tx(hal) i2s_ll_tx_stop((hal)->dev) void i2s_hal_stop_tx(i2s_hal_context_t *hal);
/** /**
* @brief Stop I2S rx * @brief Stop I2S rx
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
*/ */
#define i2s_hal_stop_rx(hal) i2s_ll_rx_stop((hal)->dev) void i2s_hal_stop_rx(i2s_hal_context_t *hal);
/** /**
* @brief Set the received data length to trigger `in_suc_eof` interrupt. * @brief Set the received data length to trigger `in_suc_eof` interrupt.

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | | Supported Targets | ESP32 | ESP32-S3 |
| ----------------- | ----- | | ----------------- | ----- | -------- |
# I2S Digital Microphone Recording Example # I2S Digital Microphone Recording Example
@@ -18,7 +18,7 @@ The audio is recorded into the SDCard using WAVE file format.
### Hardware Required ### Hardware Required
* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) * A development board with ESP32 or ESP32S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for power supply and programming * A USB cable for power supply and programming
* A digital microphone (SPK0838HT4H PDM output was used in this example) * A digital microphone (SPK0838HT4H PDM output was used in this example)
@@ -28,17 +28,17 @@ The default GPIO configuration is the following:
|Mic | GPIO | |Mic | GPIO |
|:---------:|:------:| |:---------:|:------:|
| PDM Clock | GPIO22 | | PDM Clock | GPIO4 |
| PDM Data | GPIO23 | | PDM Data | GPIO5 |
The SDCard is connected using SPI peripheral. The SDCard is connected using SPI peripheral.
| SPI | SDCard | GPIO | | SPI | SDCard | GPIO |
|:----:|:------:|:------:| |:----:|:------:|:------:|
| MISO | DAT0 | GPIO2 | | MISO | DAT0 | GPIO17 |
| MOSI | CMD | GPIO15 | | MOSI | CMD | GPIO16 |
| SCLK | CLK | GPIO14 | | SCLK | CLK | GPIO18 |
| CS | CD | GPIO13 | | CS | CD | GPIO19 |
To change the GPIO configuration, see the `Example Configuration` from the menuconfig. To change the GPIO configuration, see the `Example Configuration` from the menuconfig.

View File

@@ -4,25 +4,25 @@ menu "Example Configuration"
config EXAMPLE_SPI_MISO_GPIO config EXAMPLE_SPI_MISO_GPIO
int "SPI MISO GPIO" int "SPI MISO GPIO"
default 2 default 15
help help
Set the GPIO number used for MISO from SPI. Set the GPIO number used for MISO from SPI.
config EXAMPLE_SPI_MOSI_GPIO config EXAMPLE_SPI_MOSI_GPIO
int "SPI MOSI GPIO" int "SPI MOSI GPIO"
default 15 default 14
help help
Set the GPIO number used for MOSI from SPI. Set the GPIO number used for MOSI from SPI.
config EXAMPLE_SPI_SCLK_GPIO config EXAMPLE_SPI_SCLK_GPIO
int "SPI SCLK GPIO" int "SPI SCLK GPIO"
default 14 default 18
help help
Set the GPIO number used for SCLK from SPI. Set the GPIO number used for SCLK from SPI.
config EXAMPLE_SPI_CS_GPIO config EXAMPLE_SPI_CS_GPIO
int "SPI CS GPIO" int "SPI CS GPIO"
default 13 default 19
help help
Set the GPIO number used for CS from SPI. Set the GPIO number used for CS from SPI.
@@ -36,13 +36,13 @@ menu "Example Configuration"
help help
Set the I2S channel number. Set the I2S channel number.
config EXAMPLE_AUDIO_SAMPLE_RATE config EXAMPLE_SAMPLE_RATE
int "Audio Sample Rate" int "Audio Sample Rate"
default 44100 default 44100
help help
Set the audio sample rate frequency. Usually 16000 or 44100 Hz. Set the audio sample rate frequency. Usually 16000 or 44100 Hz.
config EXAMPLE_AUDIO_BIT_SAMPLE config EXAMPLE_BIT_SAMPLE
int "Audio Bit Sample" int "Audio Bit Sample"
default 16 default 16
help help
@@ -50,13 +50,13 @@ menu "Example Configuration"
config EXAMPLE_I2S_DATA_GPIO config EXAMPLE_I2S_DATA_GPIO
int "I2S Data GPIO" int "I2S Data GPIO"
default 23 default 5
help help
Set the GPIO number used for transmitting/receiving data from I2S. Set the GPIO number used for transmitting/receiving data from I2S.
config EXAMPLE_I2S_CLK_GPIO config EXAMPLE_I2S_CLK_GPIO
int "I2S Clock GPIO" int "I2S Clock GPIO"
default 22 default 4
help help
Set the GPIO number used for the clock line from I2S. Set the GPIO number used for the clock line from I2S.

View File

@@ -8,30 +8,28 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "driver/i2s.h" #include "driver/i2s.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_system.h"
#include <math.h>
#include "esp_log.h"
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_vfs_fat.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h" #include "driver/spi_common.h"
#include "sdmmc_cmd.h" #include "sdmmc_cmd.h"
#include "sdkconfig.h" #include "sdkconfig.h"
static const char* TAG = "pdm_rec_example"; static const char* TAG = "pdm_rec_example";
#define AUDIO_SAMPLE_SIZE (CONFIG_EXAMPLE_AUDIO_BIT_SAMPLE * 1024) #define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#define SAMPLES_NUM ((CONFIG_EXAMPLE_AUDIO_SAMPLE_RATE/100) * 2) #define NUM_CHANNELS (1) // For mono recording only!
#define BYTE_RATE (1 * CONFIG_EXAMPLE_AUDIO_SAMPLE_RATE * ((CONFIG_EXAMPLE_AUDIO_BIT_SAMPLE / 8))
#define FLASH_RECORD_SIZE (BYTE_RATE * CONFIG_EXAMPLE_REC_TIME))
#define SD_MOUNT_POINT "/sdcard" #define SD_MOUNT_POINT "/sdcard"
#define SPI_DMA_CHAN (1) #define SAMPLE_SIZE (CONFIG_EXAMPLE_BIT_SAMPLE * 1024)
#define BYTE_RATE (CONFIG_EXAMPLE_SAMPLE_RATE * (CONFIG_EXAMPLE_BIT_SAMPLE / 8)) * NUM_CHANNELS
// When testing SD and SPI modes, keep in mind that once the card has been // When testing SD and SPI modes, keep in mind that once the card has been
// initialized in SPI mode, it can not be reinitialized in SD mode without // initialized in SPI mode, it can not be reinitialized in SD mode without
@@ -39,7 +37,7 @@ static const char* TAG = "pdm_rec_example";
sdmmc_host_t host = SDSPI_HOST_DEFAULT(); sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdmmc_card_t* card; sdmmc_card_t* card;
static int16_t i2s_readraw_buff[AUDIO_SAMPLE_SIZE]; static int16_t i2s_readraw_buff[SAMPLE_SIZE];
size_t bytes_read; size_t bytes_read;
const int WAVE_HEADER_SIZE = 44; const int WAVE_HEADER_SIZE = 44;
@@ -52,17 +50,10 @@ void mount_sdcard(void)
esp_vfs_fat_sdmmc_mount_config_t mount_config = { esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true, .format_if_mount_failed = true,
.max_files = 5, .max_files = 5,
.allocation_unit_size = 16 * 1024 .allocation_unit_size = 8 * 1024
}; };
ESP_LOGI(TAG, "Initializing SD card"); ESP_LOGI(TAG, "Initializing SD card");
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
// Please check its source code and implement error recovery when developing
// production applications.
ESP_LOGI(TAG, "Using SPI peripheral");
spi_bus_config_t bus_cfg = { spi_bus_config_t bus_cfg = {
.mosi_io_num = CONFIG_EXAMPLE_SPI_MOSI_GPIO, .mosi_io_num = CONFIG_EXAMPLE_SPI_MOSI_GPIO,
.miso_io_num = CONFIG_EXAMPLE_SPI_MISO_GPIO, .miso_io_num = CONFIG_EXAMPLE_SPI_MISO_GPIO,
@@ -87,8 +78,7 @@ void mount_sdcard(void)
if (ret != ESP_OK) { if (ret != ESP_OK) {
if (ret == ESP_FAIL) { if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. " ESP_LOGE(TAG, "Failed to mount filesystem.");
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else { } else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). " ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
@@ -100,11 +90,11 @@ void mount_sdcard(void)
sdmmc_card_print_info(stdout, card); sdmmc_card_print_info(stdout, card);
} }
void wavHeader(char* wav_header, uint32_t wav_size, uint32_t sample_rate){ void generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate){
// See this for reference: http://soundfile.sapp.org/doc/WaveFormat/ // See this for reference: http://soundfile.sapp.org/doc/WaveFormat/
uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8; uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8;
uint32_t byte_rate = 1 * CONFIG_EXAMPLE_AUDIO_SAMPLE_RATE * (CONFIG_EXAMPLE_AUDIO_BIT_SAMPLE / 8); uint32_t byte_rate = BYTE_RATE;
const char set_wav_header[] = { const char set_wav_header[] = {
'R','I','F','F', // ChunkID 'R','I','F','F', // ChunkID
@@ -125,14 +115,16 @@ const char set_wav_header[] = {
memcpy(wav_header, set_wav_header, sizeof(set_wav_header)); memcpy(wav_header, set_wav_header, sizeof(set_wav_header));
} }
void record_wav(void) void record_wav(uint32_t rec_time)
{ {
// Use POSIX and C standard library functions to work with files. // Use POSIX and C standard library functions to work with files.
int flash_wr_size = 0; int flash_wr_size = 0;
ESP_LOGI(TAG, "Opening file"); ESP_LOGI(TAG, "Opening file");
char wav_header_fmt[WAVE_HEADER_SIZE]; char wav_header_fmt[WAVE_HEADER_SIZE];
wavHeader(wav_header_fmt, FLASH_RECORD_SIZE, CONFIG_EXAMPLE_AUDIO_SAMPLE_RATE);
uint32_t flash_rec_time = BYTE_RATE * rec_time;
generate_wav_header(wav_header_fmt, flash_rec_time, CONFIG_EXAMPLE_SAMPLE_RATE);
// First check if file exists before creating a new file. // First check if file exists before creating a new file.
struct stat st; struct stat st;
@@ -152,9 +144,9 @@ void record_wav(void)
fwrite(wav_header_fmt, 1, WAVE_HEADER_SIZE, f); fwrite(wav_header_fmt, 1, WAVE_HEADER_SIZE, f);
// Start recording // Start recording
while (flash_wr_size < FLASH_RECORD_SIZE) { while (flash_wr_size < flash_rec_time) {
// Read the RAW samples from the microphone // Read the RAW samples from the microphone
i2s_read(CONFIG_EXAMPLE_I2S_CH, (char *)i2s_readraw_buff, AUDIO_SAMPLE_SIZE, &bytes_read, portMAX_DELAY); i2s_read(CONFIG_EXAMPLE_I2S_CH, (char *)i2s_readraw_buff, SAMPLE_SIZE, &bytes_read, 100);
// Write the samples to the WAV file // Write the samples to the WAV file
fwrite(i2s_readraw_buff, 1, bytes_read, f); fwrite(i2s_readraw_buff, 1, bytes_read, f);
flash_wr_size += bytes_read; flash_wr_size += bytes_read;
@@ -173,27 +165,32 @@ void record_wav(void)
void init_microphone(void) void init_microphone(void)
{ {
// Set the I2S configuration as PDM and 16bits per sample
i2s_config_t i2s_config = { i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM, .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM,
.sample_rate = CONFIG_EXAMPLE_AUDIO_SAMPLE_RATE, .sample_rate = CONFIG_EXAMPLE_SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S, .communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
.dma_buf_count = 64, .dma_buf_count = 8,
.dma_buf_len = 1024, .dma_buf_len = 200,
.use_apll = 1 .use_apll = 0,
}; };
i2s_pin_config_t pin_config; // Set the pinout configuration (set using menuconfig)
pin_config.bck_io_num = I2S_PIN_NO_CHANGE; i2s_pin_config_t pin_config = {
pin_config.ws_io_num = CONFIG_EXAMPLE_I2S_CLK_GPIO; .mck_io_num = I2S_PIN_NO_CHANGE,
pin_config.data_out_num = I2S_PIN_NO_CHANGE; .bck_io_num = I2S_PIN_NO_CHANGE,
pin_config.data_in_num = CONFIG_EXAMPLE_I2S_DATA_GPIO; .ws_io_num = CONFIG_EXAMPLE_I2S_CLK_GPIO,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = CONFIG_EXAMPLE_I2S_DATA_GPIO,
};
i2s_driver_install(CONFIG_EXAMPLE_I2S_CH, &i2s_config, 0, NULL); // Call driver installation function before any I2S R/W operation.
i2s_set_pin(CONFIG_EXAMPLE_I2S_CH, &pin_config); ESP_ERROR_CHECK( i2s_driver_install(CONFIG_EXAMPLE_I2S_CH, &i2s_config, 0, NULL) );
i2s_set_clk(CONFIG_EXAMPLE_I2S_CH, CONFIG_EXAMPLE_AUDIO_SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); ESP_ERROR_CHECK( i2s_set_pin(CONFIG_EXAMPLE_I2S_CH, &pin_config) );
ESP_ERROR_CHECK( i2s_set_clk(CONFIG_EXAMPLE_I2S_CH, CONFIG_EXAMPLE_SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO) );
} }
void app_main(void) void app_main(void)
@@ -205,5 +202,7 @@ void app_main(void)
init_microphone(); init_microphone();
ESP_LOGI(TAG, "Starting recording for %d seconds!", CONFIG_EXAMPLE_REC_TIME); ESP_LOGI(TAG, "Starting recording for %d seconds!", CONFIG_EXAMPLE_REC_TIME);
// Start Recording // Start Recording
record_wav(); record_wav(CONFIG_EXAMPLE_REC_TIME);
// Stop I2S driver and destroy
ESP_ERROR_CHECK( i2s_driver_uninstall(CONFIG_EXAMPLE_I2S_CH) );
} }

View File

@@ -1517,7 +1517,6 @@ components/hal/esp32c3/include/hal/gpspi_flash_ll.h
components/hal/esp32c3/include/hal/hmac_hal.h components/hal/esp32c3/include/hal/hmac_hal.h
components/hal/esp32c3/include/hal/hmac_ll.h components/hal/esp32c3/include/hal/hmac_ll.h
components/hal/esp32c3/include/hal/i2c_ll.h components/hal/esp32c3/include/hal/i2c_ll.h
components/hal/esp32c3/include/hal/i2s_ll.h
components/hal/esp32c3/include/hal/interrupt_controller_ll.h components/hal/esp32c3/include/hal/interrupt_controller_ll.h
components/hal/esp32c3/include/hal/ledc_ll.h components/hal/esp32c3/include/hal/ledc_ll.h
components/hal/esp32c3/include/hal/memprot_ll.h components/hal/esp32c3/include/hal/memprot_ll.h
@@ -1555,7 +1554,6 @@ components/hal/esp32h2/include/hal/gpspi_flash_ll.h
components/hal/esp32h2/include/hal/hmac_hal.h components/hal/esp32h2/include/hal/hmac_hal.h
components/hal/esp32h2/include/hal/hmac_ll.h components/hal/esp32h2/include/hal/hmac_ll.h
components/hal/esp32h2/include/hal/i2c_ll.h components/hal/esp32h2/include/hal/i2c_ll.h
components/hal/esp32h2/include/hal/i2s_ll.h
components/hal/esp32h2/include/hal/interrupt_controller_ll.h components/hal/esp32h2/include/hal/interrupt_controller_ll.h
components/hal/esp32h2/include/hal/ledc_ll.h components/hal/esp32h2/include/hal/ledc_ll.h
components/hal/esp32h2/include/hal/memprot_ll.h components/hal/esp32h2/include/hal/memprot_ll.h
@@ -1634,7 +1632,6 @@ components/hal/esp32s3/include/hal/gdma_ll.h
components/hal/esp32s3/include/hal/gpio_ll.h components/hal/esp32s3/include/hal/gpio_ll.h
components/hal/esp32s3/include/hal/gpspi_flash_ll.h components/hal/esp32s3/include/hal/gpspi_flash_ll.h
components/hal/esp32s3/include/hal/i2c_ll.h components/hal/esp32s3/include/hal/i2c_ll.h
components/hal/esp32s3/include/hal/i2s_ll.h
components/hal/esp32s3/include/hal/interrupt_controller_ll.h components/hal/esp32s3/include/hal/interrupt_controller_ll.h
components/hal/esp32s3/include/hal/lcd_ll.h components/hal/esp32s3/include/hal/lcd_ll.h
components/hal/esp32s3/include/hal/ledc_ll.h components/hal/esp32s3/include/hal/ledc_ll.h
@@ -1669,7 +1666,6 @@ components/hal/gdma_hal.c
components/hal/gpio_hal.c components/hal/gpio_hal.c
components/hal/i2c_hal.c components/hal/i2c_hal.c
components/hal/i2c_hal_iram.c components/hal/i2c_hal_iram.c
components/hal/i2s_hal.c
components/hal/include/hal/adc_hal.h components/hal/include/hal/adc_hal.h
components/hal/include/hal/adc_types.h components/hal/include/hal/adc_types.h
components/hal/include/hal/aes_hal.h components/hal/include/hal/aes_hal.h
@@ -1689,7 +1685,6 @@ components/hal/include/hal/gpio_hal.h
components/hal/include/hal/gpio_types.h components/hal/include/hal/gpio_types.h
components/hal/include/hal/i2c_hal.h components/hal/include/hal/i2c_hal.h
components/hal/include/hal/i2c_types.h components/hal/include/hal/i2c_types.h
components/hal/include/hal/i2s_hal.h
components/hal/include/hal/i2s_types.h components/hal/include/hal/i2s_types.h
components/hal/include/hal/interrupt_controller_hal.h components/hal/include/hal/interrupt_controller_hal.h
components/hal/include/hal/interrupt_controller_types.h components/hal/include/hal/interrupt_controller_types.h