首先要在芯片存储区建立存储区域,这个加到partitions.csvz最后

spiffs, data, spiffs, 0xD00000, 1M
下来就是在CMakeLists.txt中增加自动烧录配置
# 配置 SPIFFS 自动烧录(关键代码)
spiffs_create_partition_image(spiffs data FLASH_IN_PROJECT)
音频文件放在data文件夹下面

这个文件夹是我置顶的烧录到映像区域的文件
下面这个是头文件和配置硬件,我用的是ns416
8
// *************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_vfs.h"
#include "esp_spiffs.h" // 添加SPIFFS支持
// -------------------------- 配置参数(根据硬件修改) --------------------------
#define I2S_BCLK GPIO_NUM_15 // I2S时钟线引脚
#define I2S_WS GPIO_NUM_16 // I2S声道选择线(LRCK)引脚
#define I2S_DOUT GPIO_NUM_7 // I2S数据输出引脚
#define PLAY_BUFFER_SIZE 2048 // 播放缓冲区大小(2KB,可按需调整)
#define WAV_SAMPLE_RATE 16000 // 目标WAV采样率(16kHz,需与播放文件匹配)
#define WAV_BIT_DEPTH 16 // 目标WAV位深(16bit,需与播放文件匹配)
/***************************************************************/
下面是播放和测试分区文件的代码
头文件
/*******************************************************/
void list_spiffs_files();
int init_ok = 0;
esp_err_t spiffs_init();
// 新增:WAV播放相关配置(需与你的WAV文件匹配)
static const int WAV_BUFFER_SIZE = 2048; // 播放缓冲区大小(2KB,可调整)
static const int WAV_HEADER_SIZE = 44; // 标准WAV文件头大小(固定44字节)
// 新增:核心函数声明(读取WAV并播放)
bool read_wav_and_play(const char* wav_path); // 读取WAV文件并调用Write播放
/*******************************************************/
类文件
void AudioCodec::OutputData(std::vector<int16_t>& data) {
//Write(data.data(), data.size());
ESP_LOGE(TAG, "++++++++++++OutputData+++++++++++++");
// 确保先初始化(只在首次调用时执行)
if (this->spiffs_init() != ESP_OK) {
return; // 初始化失败则退出
}
// 2. 调用核心函数:读取WAV并播放(路径替换为你的WAV文件名)
const char* wav_path = "/spiffs/hi_idf_audio.wav"; // SPIFFS中的WAV路径
this->read_wav_and_play(wav_path);
}
/****************************************************************************/
// -------------------------- SPIFFS初始化 --------------------------
esp_err_t AudioCodec::spiffs_init(void) {
if (this->init_ok) return ESP_OK; // 已初始化直接返回
// SPIFFS配置(指定spiffs分区)
esp_vfs_spiffs_conf_t conf = {
.base_path = "/spiffs",
.partition_label = "spiffs",
.max_files = 5,
.format_if_mount_failed = true
};
// 执行初始化
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SPIFFS初始化失败: %s", esp_err_to_name(ret));
return ret;
}
this->init_ok = 1; // 标记为已初始化
ESP_LOGI(TAG, "SPIFFS初始化成功");
// 每次调用都打印文件清单
DIR *dir = opendir("/spiffs");
if (!dir) {
ESP_LOGE(TAG, "无法打开SPIFFS目录");
return ret;
}
struct dirent *entry;
int count = 0;
ESP_LOGI(TAG, "=== 文件清单 ===");
while ((entry = readdir(dir))) {
if (entry->d_name[0] == '.') continue; // 跳过.和..
ESP_LOGI(TAG, "文件: %s", entry->d_name);
count++;
}
closedir(dir);
ESP_LOGI(TAG, "共%d个文件 ====", count);
return ESP_OK;
}
// 核心函数:读取SPIFFS中的WAV文件,调用Write播放
bool AudioCodec::read_wav_and_play(const char* wav_path) {
// 1. 打开WAV文件(SPIFFS路径,只读模式)
FILE* wav_fp = fopen(wav_path, "rb");
if (wav_fp == NULL) {
ESP_LOGE(TAG, "打开WAV失败: %s", wav_path);
return false;
}
// 2. 跳过WAV文件头(前44字节是格式信息,不是PCM数据)
if (fseek(wav_fp, WAV_HEADER_SIZE, SEEK_SET) != 0) {
ESP_LOGE(TAG, "跳过WAV头失败");
fclose(wav_fp);
return false;
}
// 3. 分配缓冲区(栈外分配,避免栈溢出)
int16_t* wav_buffer = (int16_t*)malloc(WAV_BUFFER_SIZE);
if (wav_buffer == NULL) {
ESP_LOGE(TAG, "分配WAV缓冲区失败");
fclose(wav_fp);
return false;
}
// 4. 循环读取WAV数据并播放(核心逻辑)
size_t read_samples = 0; // 每次读取的PCM样本数(16bit=1个样本)
bool play_success = true;
while (1) {
// 读取数据:fread返回字节数,转成样本数(1样本=2字节)
read_samples = fread(wav_buffer, sizeof(int16_t), WAV_BUFFER_SIZE / sizeof(int16_t), wav_fp);
if (read_samples == 0) {
// 读取到文件末尾,播放完成
ESP_LOGI(TAG, "WAV播放完成");
break;
}
// 调用Write函数,将PCM数据写入I2S(播放)
int written_samples = Write(wav_buffer, read_samples);
if (written_samples != read_samples) {
ESP_LOGE(TAG, "播放数据丢失:读取%d样本,写入%d样本", read_samples, written_samples);
play_success = false;
break;
}
// (可选)打印播放进度(调试用)
ESP_LOGD(TAG, "播放进度:已读%d样本", read_samples);
}
// 5. 释放资源
free(wav_buffer);
fclose(wav_fp);
return play_success;
}
/****************************************************************************/
大体就是这样,因为嵌入别的代码的一部分,不能直接使用,可以借鉴。