【 声明版权所有欢迎转载请勿用于商业用途。 联系信箱feixiaoxing 163.com】在esp32开发的时候其实rom区域的大小是一定的。也就是说codedata生成的bin文件大小是一定的。但是整个esp32的flash还是挺大的所以如果要存储文件的话最好是单独创建一个分区然后操作这个分区即可。1、调整flash大小idf上面默认flash的大小都是2m所以需要在menuconfig下面把flash大小调整为4m。在Serial Flash Config里面调整下即可。2、创建partitions.csv文件之前是没有这个文件的现在需要单独创建这个文件。# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 0x100000, storage, data, spiffs, , 0x100000,3、csv文件的存放位置csv文件放到prj根目录下即可不需要放到main的子目录下。4、用ai创建代码为了验证分区是否ok可以创建一个demo比如录制一个10s的wav文件放到这个分区确认是否ok。如果整个流程没有问题的话那么就说明分区是可以的。#include stdio.h #include string.h #include math.h #include freertos/FreeRTOS.h #include freertos/task.h #include esp_log.h #include esp_spiffs.h #include driver/i2s_pdm.h static const char *TAG PDM_MIC; // ------- Configuration ------- #define PDM_CLK_GPIO GPIO_NUM_4 #define PDM_DATA_GPIO GPIO_NUM_5 #define SAMPLE_RATE 16000 #define BITS_PER_SAMPLE 16 #define NUM_CHANNELS 1 #define RECORD_SECONDS 10 #define READ_CHUNK_SAMPLES 1024 // samples per read #define WAV_FILE_PATH /spiffs/record.wav static i2s_chan_handle_t rx_chan NULL; // ---------- Standard 44-byte WAV header ---------- typedef struct __attribute__((packed)) { char riff_id[4]; // RIFF uint32_t riff_size; // file size - 8 char wave_id[4]; // WAVE char fmt_id[4]; // fmt uint32_t fmt_size; // 16 for PCM uint16_t audio_format; // 1 PCM uint16_t num_channels; uint32_t sample_rate; uint32_t byte_rate; // sample_rate * num_channels * bits_per_sample/8 uint16_t block_align; // num_channels * bits_per_sample/8 uint16_t bits_per_sample; char data_id[4]; // data uint32_t data_size; // number of bytes of audio data } wav_header_t; static void wav_header_init(wav_header_t *h, uint32_t data_size) { memcpy(h-riff_id, RIFF, 4); h-riff_size data_size sizeof(wav_header_t) - 8; memcpy(h-wave_id, WAVE, 4); memcpy(h-fmt_id, fmt , 4); h-fmt_size 16; h-audio_format 1; // PCM h-num_channels NUM_CHANNELS; h-sample_rate SAMPLE_RATE; h-bits_per_sample BITS_PER_SAMPLE; h-block_align h-num_channels * h-bits_per_sample / 8; h-byte_rate h-sample_rate * h-block_align; memcpy(h-data_id, data, 4); h-data_size data_size; } // ---------- SPIFFS init ---------- static void spiffs_init(void) { esp_vfs_spiffs_conf_t conf { .base_path /spiffs, .partition_label NULL, .max_files 5, .format_if_mount_failed true, }; ESP_ERROR_CHECK(esp_vfs_spiffs_register(conf)); size_t total 0, used 0; esp_spiffs_info(NULL, total, used); ESP_LOGI(TAG, SPIFFS mounted, total%d used%d, (int)total, (int)used); } // ---------- PDM mic init ---------- static void pdm_mic_init(void) { i2s_chan_config_t chan_cfg I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(chan_cfg, NULL, rx_chan)); i2s_pdm_rx_config_t pdm_rx_cfg { .clk_cfg I2S_PDM_RX_CLK_DEFAULT_CONFIG(SAMPLE_RATE), .slot_cfg I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg { .clk PDM_CLK_GPIO, .din PDM_DATA_GPIO, .invert_flags { .clk_inv false }, }, }; pdm_rx_cfg.slot_cfg.slot_mask I2S_PDM_SLOT_LEFT; ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_chan, pdm_rx_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(rx_chan)); ESP_LOGI(TAG, PDM mic init done, CLK%d, DATA%d, %dHz, PDM_CLK_GPIO, PDM_DATA_GPIO, SAMPLE_RATE); } // ---------- Record N seconds to a WAV file ---------- static void record_wav_task(void *arg) { const uint32_t total_samples SAMPLE_RATE * RECORD_SECONDS * NUM_CHANNELS; const uint32_t total_bytes total_samples * (BITS_PER_SAMPLE / 8); FILE *f fopen(WAV_FILE_PATH, wb); if (!f) { ESP_LOGE(TAG, Failed to open %s for writing, WAV_FILE_PATH); vTaskDelete(NULL); return; } // Write a placeholder header first, fix up data_size after recording wav_header_t header; wav_header_init(header, total_bytes); fwrite(header, sizeof(header), 1, f); int16_t *buf malloc(READ_CHUNK_SAMPLES * sizeof(int16_t)); if (!buf) { ESP_LOGE(TAG, malloc failed); fclose(f); vTaskDelete(NULL); return; } uint32_t bytes_written 0; ESP_LOGI(TAG, Recording %d seconds..., RECORD_SECONDS); while (bytes_written total_bytes) { size_t bytes_read 0; uint32_t bytes_remaining total_bytes - bytes_written; size_t want READ_CHUNK_SAMPLES * sizeof(int16_t); if (want bytes_remaining) { want bytes_remaining; // last chunk may be smaller } esp_err_t ret i2s_channel_read(rx_chan, buf, want, bytes_read, portMAX_DELAY); if (ret ! ESP_OK) { ESP_LOGW(TAG, i2s read err: %d, ret); continue; } fwrite(buf, 1, bytes_read, f); bytes_written bytes_read; } fclose(f); free(buf); ESP_LOGI(TAG, Recording done: %s (%d bytes audio data), WAV_FILE_PATH, (int)bytes_written); vTaskDelete(NULL); } void app_main(void) { spiffs_init(); pdm_mic_init(); xTaskCreate(record_wav_task, record_wav_task, 4096, NULL, 5, NULL); }5、编译测试编译的话就按照一般的idf编译方法去处理就好了。调试的话主要看打印。可以看到第一次spiffs mount不成功还会格式化一下。后续再调试的话就直接加载了。