Sound dan ESP32 – 2

Melanjutkan dari modul sebelumnya, pada modul ini kita akan merangkai komponen dan membuat aplikasi untuk menjalankan file sound atau music.

Component

  • MAX98357 amplifier module
  • Speaker (impedance >= 4 ohm)

Diagram

Code

Buat file include/app.h untuk mendefinisikan wav_header struct.

#ifndef app_h_
#define app_h_

typedef struct
{
    char riff_header[4]; 
    int wav_size;        
    char wave_header[4]; 
    
    char fmt_header[4]; 
    int fmt_chunk_size; 
    short audio_format; 
    short num_channels;
    int sample_rate;
    int byte_rate;          
    short sample_alignment; 
    short bit_depth;        
    
    char data_header[4]; 
    int data_bytes;      
} wav_header_t;

#endif

Kemudian buka main.c, ganti code dari modul sebelumnya dengan code dibawah.

//bagian import library
#include "app.h"
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>
#include "esp_spiffs.h"
#include "esp_err.h"
#include "driver/i2s.h"
#include "hal/i2s_types.h"
#define BCLK_PIN 25
#define LRC_PIN 26
#define DIN_PIN 22
static const int i2s_num = I2S_NUM_0;
static uint8_t buff[1024];
static FILE *wav_fp;


//bagian init hardware
static esp_err_t init_hw(void)
{
    printf("Initializing SPIFFS\n");
    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = true
    };
    return esp_vfs_spiffs_register(&conf);
}


//bagian open file
static esp_err_t open_file(wav_header_t *header)
{
    wav_fp = fopen("/spiffs/rooster.wav", "rb");
    if (wav_fp == NULL)
    {
        printf("err: no file\n");
        return ESP_ERR_INVALID_ARG;
    }
    fread((void *)header, sizeof(wav_header_t), 1, wav_fp);
    printf("Wav format:\n");
    printf("bit_depth: %d\n", header->bit_depth);
    printf("num_channels: %d\n", header->num_channels);
    printf("sample_rate: %d\n", header->sample_rate);
    return ESP_OK;
}

//bagian ini i2s
static esp_err_t init_i2s(wav_header_t *header)
{
    esp_err_t err;
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_TX,
        .sample_rate = header->sample_rate,
        .bits_per_sample = header->bit_depth,
        .communication_format = I2S_COMM_FORMAT_I2S_MSB,
        .channel_format = header->num_channels == 2 ? I2S_CHANNEL_FMT_RIGHT_LEFT : I2S_CHANNEL_FMT_ONLY_LEFT,
        .intr_alloc_flags = 0,
        .dma_buf_count = 2,
        .dma_buf_len = 1024,
        .use_apll = 1,
    };

    err = i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
    if (err != ESP_OK)
    {
        return err;
    }

    i2s_pin_config_t pin_config = {
        .bck_io_num = BCLK_PIN,
        .ws_io_num = LRC_PIN,
        .data_out_num = DIN_PIN,
        .data_in_num = I2S_PIN_NO_CHANGE,
    };
    err = i2s_set_pin(i2s_num, &pin_config);
    if (err != ESP_OK)
    {
       return err;
    }

    return i2s_zero_dma_buffer(i2s_num);
}


//bagian main func
void app_main(void)
{
    esp_err_t ret;
    ret = init_hw();
    if (ret != ESP_OK)
    {
        printf("err: %s\n", esp_err_to_name(ret));
        return;
    }
    wav_header_t header;
    ret = open_file(&header);
    if (ret != ESP_OK)
    {
        printf("err: %s\n", esp_err_to_name(ret));
        return;
    }

    ret = init_i2s(&header);
    if (ret != ESP_OK)
    {
        printf("err: %s\n", esp_err_to_name(ret));
        return;
    }

    size_t bytes_written;
    size_t cnt;
    while (1)
    {
        cnt = fread(buff, 1, sizeof(buff), wav_fp);
        ret = i2s_write(i2s_num, (const void *)buff,
        sizeof(buff), &bytes_written, portMAX_DELAY);
        if (ret != ESP_OK)
        {
            printf("err: %s\n", esp_err_to_name(ret));
            break;
        }
        if (cnt < sizeof(buff))
        {
            break;
        }
    }
    fclose(wav_fp);
    i2s_driver_uninstall(i2s_num);
}

Penjelasan Code

Bagian Import library

Header file untuk I2S driver adalah driver/i2s.h. Disini kita definisikan pins dan constant untuk perangkat I2S dengan nilai I2S_NUM_0. Kita juga buat variable untuk sound file dan sound data buffer.

Bagian init hardware
Pada bagian ini kita hanya inisialisasi spiffs partition.

Bagian Open File

Disini kita buka file sound yang tersimpan pada spiffs partition dan baca WAV header. Setiap WAV file terdapat metadata yang berisi informasi file tersebut. Kita akan gunakan informasi tersebut.
Sample rate atau number of samples dalam satu detik.
Bit depth atau number of bits per sample (ADC resolution)
Jumlah channel, single channle atau dua channels untuk kiri dan kanan.

Bagian Inisialisasi I2S

Fungsi init_i2s akan memerlukan parameter metadata yang kita baca pada fungsi open file.

Pada fungsi, kita akan membuat configuration variable dengan type i2s_config_t, yang akan berisi field yang akan digunakan oleh perangkat I2S dan property dari sound file yang akan dimainkan.

Kita juga perlu spesifisikan agar perangkat I2S menggunakan direct memory access (DMA).

Setelah variable didefinisikan, kita gunaka perintah i2s_driver_install untuk mengkonfigurasi driver.

Lalu kita set pins yang digunakan oleh perangkat I2S peripheral dengan perintah i2s_set_pin.

Terakhir kita reset DMA buffer.

Bagian main function

Pertama kita inisialisasi SPIFFS driver melalui fungsi init_hw, kemudian buka file dengan menjalankan fungsi open_file.
Selanjutnya inisialisasi I2S dengan menajalankan fungsi init_i2s.

Setelah inisialisasi berhasil, kita sudah siap menjalankan sound.

Pada while loop, kita baca dari file into buff, dan gunakan perintah i2s_write untuk mengirim sound data ke I2S interface melalui DMA buffer.

Setelah seluruh data sudah ditranser, kita dapat tutup file dan uninstall I2S driver dengan perintah i2s_driver_uninstall.

Sampai disini, kita sudah berhasil menjalankan file sound/music. Pada modul berikutnya kita akan mempelajari menggunakan camera sensor.

Sharing is caring:

Leave a Comment