[ESP32] I2S播放wav文件

 //代码:循环播放4首内置的wav音乐,I2S连接d类功放用NS4168芯片

//文件取样格式:Wave PCM 签字的 16bit, 采样频率:16KHz ,比特率705kbps

//demo工程打包下载:https://download.csdn.net/download/wabil/89515015

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "esp_system.h"
#include "esp_check.h"
#include "esp_log.h"

/* Example configurations */
#define EXAMPLE_SAMPLE_RATE (16000) // 16KHZ
#define EXAMPLE_MCLK_MULTIPLE (384) // If not using 24-bit data width, 256 should be enough
#define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE)
#define EXAMPLE_VOICE_VOLUME CONFIG_EXAMPLE_VOICE_VOLUME

/* I2S port and GPIOs */
#define I2S_NUM (0)
#define I2S_MCK_IO (GPIO_NUM_1)   //[No used]
#define I2S_BCK_IO (GPIO_NUM_36) // SerialCK
#define I2S_WS_IO (GPIO_NUM_35)  // LRCK
#define I2S_DO_IO (GPIO_NUM_37)  // SDATA out
#define I2S_DI_IO (GPIO_NUM_19)  // SDATA in for micphone [No used]

static const char *TAG = "i2s_ns4168";
static const char err_reason[][30] = {"input param is invalid", "operation timeout"};
static i2s_chan_handle_t tx_handle = NULL;
static i2s_chan_handle_t rx_handle = NULL;

/* Import music file as buffer */

#define DECLARE_WAV_START(SND) extern const uint8_t SND##_wav_start[] asm("_binary_" #SND "_wav_start")
#define DECALARE_WAV_END(SND) extern const uint8_t SND##_wav_end[] asm("_binary_" #SND "_wav_end")

DECLARE_WAV_START(Snd01);
DECALARE_WAV_END(Snd01);

DECLARE_WAV_START(Snd02);
DECALARE_WAV_END(Snd02);

DECLARE_WAV_START(Snd03);
DECALARE_WAV_END(Snd03);

DECLARE_WAV_START(Snd_Hotel); // california_hotel
DECALARE_WAV_END(Snd_Hotel);

const uint8_t *music_group[][2] = {
    {&Snd01_wav_start, &Snd01_wav_end},
    {&Snd02_wav_start, &Snd02_wav_end},
    {&Snd03_wav_start, &Snd03_wav_end},
    {&Snd_Hotel_wav_start, &Snd_Hotel_wav_end},

};

esp_err_t play_snd_id(uint8_t snd_id, uint32_t timeout_ms)
{
    uint8_t *data_ptr_start = (uint8_t *)music_group[snd_id][0];
    uint8_t *data_ptr_end = (uint8_t *)music_group[snd_id][1];
    size_t data_len = data_ptr_end - data_ptr_start;
    uint32_t bytes_write = 0;

   // ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    vTaskDelay(150 / portTICK_PERIOD_MS);
    uint32_t tick1 = esp_log_timestamp();
    printf("[%ld] read to play:%d ,length:%d bytes.\n", tick1, snd_id, data_len);
    esp_err_t ret = i2s_channel_write(tx_handle, data_ptr_start, data_len, &bytes_write, timeout_ms);
    uint32_t tick2 = esp_log_timestamp();
    printf("[%ld] end play,written:%ld,take:%ld ms\n", tick2,bytes_write, tick2 - tick1);
    vTaskDelay(150 / portTICK_PERIOD_MS);
  //  ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));

    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "[music] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
        abort();
    }
    if (bytes_write <= 0)
    {
        ESP_LOGE(TAG, "[music] i2s music play failed.");
        abort();
    }

    return ret;
}

static esp_err_t i2s_driver_init(void)
{
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER);
    chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer
    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
        .gpio_cfg = {
            .mclk = I2S_MCK_IO,
            .bclk = I2S_BCK_IO,
            .ws = I2S_WS_IO,
            .dout = I2S_DO_IO,
            .din = I2S_DI_IO,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };
    std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE;

    ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));

    return ESP_OK;
}

static void i2s_music_task(void *args)
{
    esp_err_t ret = ESP_OK;
    size_t bytes_write = 0;
    uint8_t *data_ptr = (uint8_t *)Snd01_wav_start;

    bytes_write = Snd01_wav_end - Snd01_wav_start;
    printf("the music bin data length:%d bytes.start_addr:%p\n", bytes_write, data_ptr);

    /* (Optional) Disable TX channel and preload the data before enabling the TX channel,
     * so that the valid data can be transmitted immediately */

    ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
    ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, Snd01_wav_end - data_ptr, &bytes_write));
    //  data_ptr += bytes_write;  // Move forward the data pointer
    printf("preload data length:%d.EXAMPLE_SAMPLE_RATE=%d\n", bytes_write, EXAMPLE_SAMPLE_RATE);

    /* Enable the TX channel */
    ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
   vTaskDelay(5000 / portTICK_PERIOD_MS);
    uint8_t snd_id = 0;
    while (1)
    {

        play_snd_id(snd_id, portMAX_DELAY);
        snd_id = (snd_id + 1) % 4; // 共4个wav音效
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    // 634240 bytes are written
    printf("I2S_NS4168: BCK=%d,WS=%d,DAT_IO=%d.\n", I2S_BCK_IO, I2S_WS_IO, I2S_DO_IO);

    /* Initialize i2s peripheral */
    if (i2s_driver_init() != ESP_OK)
    {
        ESP_LOGE(TAG, "i2s driver init failed");
        abort();
    }
    else
    {
        ESP_LOGI(TAG, "i2s driver init success");
    }
    xTaskCreate(i2s_music_task, "i2s_music_task", 4096, NULL, 5, NULL);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值