Kỹ thuật điện tử & Điện lạnh

Lập trình ESP-IDF giao tiếp với file âm thanh sử dụng giao thức I2S (P2) kiến thức mới năm 2023

Lập trình ESP-IDF giao tiếp với file âm thanh sử dụng giao thức I2S (P2) – Cập nhật kiến thức mới nhất năm 2023

Sau khi thêm tệp âm thanh vào phân vùng spiffs, trước tiên chúng ta cần thiết lập nguyên mẫu trên breadboard, như thường lệ. Các thành phần như sau:
• Một mô-đun bộ khuếch đại MAX98357
• Một loa (trở kháng> = 4 ohm)
Hình sau cho thấy sơ đồ phần cứng của thiết lập của chúng ta :

Sau đây là code phần ứng dụng chạy file âm thanh :

#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;

Tệp tiêu đề cho trình điều khiển I2S là trình điều khiển / i2s.h. Chúng ta xác định các chân I2S và một hằng số cho thiết bị ngoại vi I2S với giá trị I2S_NUM_0. Chúng ta cũng tạo các biến cho tệp âm thanh và bộ đệm dữ liệu âm thanh sẽ được sử dụng trong ứng dụng. Trong hàm init_hw, chúng tôi chỉ khởi tạo phân vùng spiffs, như sau:

 

static esp_err_t init_hw(void)
{
printf("Initializing SPIFFSn");
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);
}

Chúng ta cần một hàm để mở file âm thanh. Ta tiến hành như sau :

 

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

Trong open_file, chúng ta mở tệp âm thanh được lưu trữ bên trong phân vùng spiffs và đọc tiêu đề WAV trong tệp. Mọi tệp WAV đều chứa thông tin siêu dữ liệu về dữ liệu âm thanh thực tế. Chúng ta sẽ sử dụng một số thông tin có trong tiêu đề này trong khi cấu hình thiết bị ngoại vi I2S cho đầu ra. Thông tin này như sau:
• Tốc độ lấy mẫu hoặc số lượng mẫu trong một giây
•Số lượng bit trên mỗi mẫu (độ phân giải ADC)
• Số lượng kênh; một kênh đơn hoặc hai kênh cho trái và phải
Chúng ta nên khởi tạo thiết bị ngoại vi I2S để phát tệp âm thanh. Đây là hàm khởi tạo:

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,
};

Hàm init_i2s lấy  dữ liệu âm thanh đến từ tệp làm đối số. Trong hàm, chúng ta tạo một biến cấu hình kiểu i2s_config_t. Biến cấu hình này có các trường khác nhau liên quan đến cách chúng ta sẽ sử dụng thiết bị ngoại vi I2S và các thuộc tính của tệp âm thanh sẽ được phát. Chúng ta cũng chỉ định rằng thiết bị ngoại vi I2S sẽ sử dụng truy cập bộ nhớ trực tiếp (DMA) để xử lý dữ liệu nhanh trực tiếp từ bộ đệm DMA. Sau khi chuẩn bị biến cấu hình, chúng ta sử dụng i2s_driver_install để định cấu hình trình điều khiển với cấu hình này:

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);
}

Vì thiết bị ngoại vi đang xuất ra, chúng ta đặt trường data_out_num của pin_config, chỉ để rõ ràng. Cuối cùng, chúng tôi đặt lại bộ đệm DMA và cấu hình I2S hoàn tất. Sau khi thực hiện tất cả các hàm khởi tạo, chúng ta có thể chuyển sang app_main. Đầu tiên, chúng ta khởi tạo trình điều khiển SPIFFS trong init_hw và mở tệp âm thanh bằng cách gọi open_file:

void app_main(void)
{
esp_err_t ret;
ret = init_hw();
if (ret != ESP_OK)
{
printf("err: %sn", esp_err_to_name(ret));
return;
}
wav_header_t header;
ret = open_file(&header);
if (ret != ESP_OK)
{
printf("err: %sn", esp_err_to_name(ret));
return;
}

Sau đó, chúng tôi khởi tạo thiết bị ngoại vi I2S với siêu dữ liệu âm thanh:

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

Quá trình khởi tạo hoàn tất và chúng ta đã sẵn sàng phát âm thanh như sau:

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: %sn", esp_err_to_name(ret));
break;
}

Trong vòng lặp while, chúng ta đọc từ tệp vào buff và chúng tôi sử dụng i2s_write để gửi dữ liệu âm thanh đến giao tiếp I2S thông qua bộ đệm DMA. Khi tất cả dữ liệu đã được chuyển, chúng tôi có thể đóng tệp và gỡ cài đặt trình điều khiển I2S bằng cách sử dụng hàm i2s_driver_uninstall:

if (cnt < sizeof(buff))
{
break;
}
}
fclose(wav_fp);
i2s_driver_uninstall(i2s_num);
}

Cuối cùng thì projects cũng hoàn thành. Chúng ta có thể tải ứng dụng lên và thưởng thức tiếng gà trống ^^.

Chúc các bạn thành công !!!

Series Navigation

<< Lập trình ESP-IDF giao tiếp với file âm thanh sử dụng giao thức I2S (P1)

Kết thúc
Ngoài các bài viết tin tức, bài báo hàng ngày của https://www.kythuatcodienlanh.com/, nguồn nội dung cũng bao gồm các bài viết từ các cộng tác viên chuyên gia đầu ngành về chuỗi kiến thức kỹ thuật điện, điện lạnh, điện tử, cơ khí,…,.. được chia sẽ chủ yếu từ nhiều khía cạnh liên quan chuỗi kiến thức này.
Bạn có thể dành thời gian để xem thêm các chuyên mục nội dung chính với các bài viết tư vấn, chia sẻ mới nhất, các tin tức gần đây từ chuyên gia và đối tác của Chúng tôi. Cuối cùng, với các kiến thức chia sẻ của bài viết, hy vọng góp phần nào kiến thức hỗ trợ cho độc giả tốt hơn trong hoạt động nghề nghiệp cá nhân!
* Ý kiến được trình bày trong bài viết này là của tác giả khách mời và không nhất thiết phải là SEMTEK. Nhân viên tác giả, cộng tác viên biên tập sẽ được liệt kê bên cuối bài viết.
Trân trọng,
Các chuyên mục nội dung liên quan

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Back to top button