esp32开发与应用(添加数据分区)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

在esp32开发的时候,其实rom区域的大小是一定的。也就是说,code+data生成的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不成功,还会格式化一下。后续再调试的话,就直接加载了。

相关推荐
嵌入式-老费2 小时前
esp32开发与应用(OTA升级)
嵌入式硬件
CYLAM20254 小时前
STC32G 单片机0.96“OLED 西历农历可调万年历 (1901-2100)
单片机·嵌入式硬件·stc32g·万年历·西历农历·0.96”oled 12864·4x4 矩阵键盘
Discipline~Hai5 小时前
ARM03-蜂鸣器和中断
c语言·arm开发·单片机·嵌入式硬件·嵌入式
KaifuZeng5 小时前
电源面试问题汇总一
单片机·嵌入式硬件·面试·电路
驱动探索者7 小时前
RISC-V PLIC 深度解析:从 Spec 到 Zephyr 驱动实现
单片机·嵌入式硬件·中断控制器
LCG元8 小时前
STM32 FreeRTOS 实战:任务调度 + 互斥锁 + 消息队列 + 串口命令解析器
stm32·单片机·嵌入式硬件
Hello_Damon_Nikola8 小时前
姿态式饮水量估算从原理到实战
嵌入式硬件
LCG元8 小时前
STM32 SPI Flash 读写实战:W25Q64 驱动 + FatFS 文件系统移植 + 日志存储系统
stm32·单片机·嵌入式硬件
不想学习!!9 小时前
【STM32 基础复习 01】初识 STM32F103ZET6:型号、封装、引脚编号与特殊引脚
stm32·单片机·嵌入式硬件