Được. Chúng ta sẽ làm Bài 1 thật chắc, chưa đụng đến AI, Wi-Fi hay speaker. Mục tiêu duy nhất của bài này là:
ESP32 WROOM-32 đọc được âm thanh từ INMP441 qua I²S và chúng ta nhìn thấy mức âm thanh thay đổi trên Serial Monitor.
INMP441 là microphone MEMS kỹ thuật số, nên không dùng analogRead() như microphone analog; ESP32 phải đọc nó qua giao tiếp I²S. (Espressif Systems)
Bài 1 — ESP32 WROOM-32 + INMP441
1. Chuẩn bị
Bạn cần:
- ESP32 WROOM-32 Dev Board 30 pin
- INMP441 module
- 6 dây jumper
- USB cable
- Arduino IDE
Nếu bạn chưa có INMP441 mà chỉ có microphone tháo từ PVX83170 thì chưa nên đấu microphone đó vào mạch này. Trước tiên chúng ta cần xác định nó là microphone analog hay digital.
2. Sơ đồ chân INMP441
INMP441 thường có 6 chân:
| INMP441 | Chức năng |
|---|---|
| VDD | nguồn |
| GND | mass |
| SCK | I²S Bit Clock |
| WS | I²S Word Select / LRCLK |
| SD | I²S Serial Data |
| L/R | chọn kênh trái/phải |
L/R = GND chọn kênh trái; L/R = 3.3V chọn kênh phải. (ShillehTek)
3. Đấu dây ESP32 → INMP441
Mình đề xuất dùng GPIO:
- GPIO26 = SCK
- GPIO25 = WS
- GPIO22 = SD
Đây là một cấu hình phổ biến cho ESP32-WROOM-32. (DeepWiki)
| ESP32 WROOM-32 | INMP441 |
|---|---|
| 3V3 | VDD |
| GND | GND |
| GPIO26 | SCK |
| GPIO25 | WS |
| GPIO22 | SD |
| GND | L/R |
Sơ đồ:
ESP32 WROOM-32 INMP441
┌───────────────┐ ┌───────────┐
│ │ │ │
│ 3V3 ───────────────────────→│ VDD │
│ │ │ │
│ GND ───────────────────────→│ GND │
│ │ │ │
│ GPIO26 ────────────────────→│ SCK │
│ │ │ │
│ GPIO25 ────────────────────→│ WS │
│ │ │ │
│ GPIO22 ←────────────────────│ SD │
│ │ │ │
│ GND ───────────────────────→│ L/R │
│ │ │ │
└───────────────┘ └───────────┘
⚠️ Đặc biệt chú ý
VDD của INMP441 nối 3.3V, không nối 5V. Nhiều tài liệu module ghi phạm vi nguồn 1.8–3.3 V. (ShillehTek)
Và L/R tuyệt đối không để hở. Ta nối xuống GND để chọn kênh trái. (ShillehTek)
4. Hiểu I²S trước khi lập trình
Đây là phần rất quan trọng cho dự án AI sau này.
Microphone không gửi cho ESP32 kiểu:
MIC → điện áp → ADC → số
mà gửi:
I²S
│
┌──────────┼──────────┐
│ │ │
↓ ↓ ↓
SCK WS SD
Clock Channel Audio
SCK
Bit clock.
ESP32 tạo clock này và microphone sử dụng nó để đồng bộ dữ liệu.
WS
Word Select.
Nó xác định slot/kênh trái-phải của I²S.
SD
Đây là dữ liệu âm thanh từ microphone → ESP32.
Vì vậy:
SCK : ESP32 → INMP441
WS : ESP32 → INMP441
SD : INMP441 → ESP32
Trong Arduino-ESP32, I²S có các chân riêng cho din và dout; microphone của chúng ta chỉ cần đường input din. (Espressif Systems)
5. Arduino IDE
Bạn đang sử dụng Arduino IDE cho ESP32, vì vậy mình khuyên dùng ESP32 Arduino Core 3.x và API ESP_I2S.h hiện tại thay vì bắt đầu bằng các ví dụ I²S cũ sử dụng API đời 1.x/2.x.
Tài liệu Arduino-ESP32 hiện tại cung cấp trực tiếp ESP_I2S.h và I2SClass. (Espressif Systems)
Trong Arduino IDE:
Tools → Board → ESP32 Arduino → ESP32 Dev Module
Chọn đúng COM của ESP32.
6. Chương trình test đầu tiên
Chúng ta chưa cần Wi-Fi.
Nạp chương trình này:
#include <Arduino.h>
#include <ESP_I2S.h>
I2SClass I2S;
// INMP441
#define I2S_SCK 26
#define I2S_WS 25
#define I2S_SD 22
#define SAMPLE_RATE 16000
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("==============================");
Serial.println(" ESP32 + INMP441 TEST");
Serial.println("==============================");
// SCK, WS, SDOUT, SDIN
// Microphone chỉ sử dụng SDIN
I2S.setPins(
I2S_SCK,
I2S_WS,
-1,
I2S_SD
);
// 16 kHz, 16-bit, stereo slots
if (!I2S.begin(
I2S_MODE_STD,
SAMPLE_RATE,
I2S_DATA_BIT_WIDTH_16BIT,
I2S_SLOT_MODE_STEREO))
{
Serial.println("ERROR: I2S BEGIN FAILED!");
while (1)
{
delay(1000);
}
}
Serial.println("I2S OK");
Serial.println("Start microphone...");
}
void loop()
{
const int BUFFER_SIZE = 128;
int16_t samples[BUFFER_SIZE];
size_t bytesRead =
I2S.readBytes(
(char *)samples,
sizeof(samples)
);
if (bytesRead == 0)
{
Serial.println("No audio data");
delay(100);
return;
}
int sampleCount = bytesRead / sizeof(int16_t);
int32_t peak = 0;
uint64_t sum = 0;
for (int i = 0; i < sampleCount; i++)
{
int32_t value = samples[i];
if (value < 0)
value = -value;
if (value > peak)
peak = value;
sum += value;
}
int32_t average = sum / sampleCount;
Serial.print("Samples: ");
Serial.print(sampleCount);
Serial.print(" | Peak: ");
Serial.print(peak);
Serial.print(" | Average: ");
Serial.println(average);
delay(100);
}
Cách cấu hình này dựa trên API I²S hiện tại của Arduino-ESP32: setPins(SCK, WS, SDOUT, SDIN) rồi begin() để thiết lập mode, sample rate, độ rộng dữ liệu và slot mode. (Espressif Systems)
7. Mở Serial Monitor
Sau khi upload:
Tools → Serial Monitor
Chọn:
115200 baud
Bạn có thể thấy kiểu:
==============================
ESP32 + INMP441 TEST
==============================
I2S OK
Start microphone...
Samples: 128 | Peak: 235 | Average: 82
Samples: 128 | Peak: 248 | Average: 91
Samples: 128 | Peak: 251 | Average: 87
Khi bạn nói gần microphone:
Samples: 128 | Peak: 1240 | Average: 380
Samples: 128 | Peak: 3510 | Average: 920
Samples: 128 | Peak: 5180 | Average: 1400
Khi bạn vỗ tay hoặc nói to gần microphone, Peak và Average phải thay đổi rõ rệt.
8. Nếu giá trị không thay đổi
Đây là phần rất quan trọng.
Nếu bạn thấy:
Peak: 0
Peak: 0
Peak: 0
Peak: 0
thì đừng vội kết luận microphone hỏng.
Kiểm tra theo thứ tự:
Kiểm tra 1 — nguồn
Dùng đồng hồ đo:
Que đỏ → INMP441 VDD
Que đen → INMP441 GND
Bạn cần khoảng:
≈ 3.3 V
Kiểm tra 2 — L/R
Phải có:
L/R → GND
Không để chân này floating.
Kiểm tra 3 — SCK
ESP32 GPIO26
│
↓
INMP441 SCK
Kiểm tra 4 — WS
ESP32 GPIO25
│
↓
INMP441 WS
Kiểm tra 5 — SD
INMP441 SD
│
↓
ESP32 GPIO22
SD là chiều ngược lại so với SCK/WS.
9. Một lỗi rất hay gặp với INMP441
Có một vấn đề khiến người mới tưởng rằng microphone hỏng:
INMP441
L/R → GND
nhưng code lại đọc right channel.
Khi đó có thể nhận được dữ liệu không đúng hoặc gần như không có âm thanh.
L/R của INMP441 chính là chân chọn slot trái/phải; GND chọn left, 3.3V chọn right. (ShillehTek)
Vì vậy trong bài này chúng ta thống nhất:
L/R = GND
10. Tại sao mình chọn 16 kHz?
Đối với voice assistant, 16 kHz là một điểm khởi đầu rất hợp lý.
SAMPLE_RATE = 16000
Có nghĩa:
16.000 mẫu / giây
Ví dụ:
"Xin chào ESP32"
sẽ được microphone biến thành chuỗi các mẫu âm thanh:
+120
+240
+510
+820
+400
-120
-450
-700
...
Sau này chúng ta sẽ đóng gói những mẫu này thành audio để gửi đến Speech-to-Text.
11. Đừng quan tâm đến “Peak” quá nhiều ở bài này
Mục tiêu hiện tại chỉ là:
Không nói
↓
giá trị nhỏ
Nói
↓
giá trị tăng
Vỗ tay
↓
giá trị tăng mạnh
Nếu đạt được điều này:
🎉 Phần microphone + I²S đã hoạt động.
12. Sau khi test thành công
Kiến trúc dự án của chúng ta sẽ tiến lên như sau:
BÀI 1
INMP441
↓
ESP32
↓
Serial Monitor
✓
↓
BÀI 2
INMP441
↓
ESP32
↓
Audio buffer
↓
WAV/PCM
✓
↓
BÀI 3
ESP32
↓ Wi-Fi
PC
↓
Audio
✓
↓
BÀI 4
Audio
↓
Speech-to-Text
↓
"Xin chào"
✓
↓
BÀI 5
"Xin chào"
↓
AI
↓
"Xin chào, tôi có thể giúp gì?"
✓
↓
BÀI 6
Text
↓
Text-to-Speech
↓
Audio
✓
↓
BÀI 7
ESP32
↓
MAX98357A
↓
Speaker
✓
↓
🎙️
↓
ESP32
↓
Wi-Fi
↓
AI
↓
ESP32
↓
🔊
Đó chính là trợ lý AI bằng giọng nói mà chúng ta đang hướng tới.
Một lưu ý cho bước tiếp theo
Nếu bạn đã mua INMP441, hãy gửi cho mình ảnh mặt trước của module INMP441 và ảnh ESP32 WROOM-32 30-pin của bạn. Có nhiều module INMP441 trên thị trường in thứ tự chân khác nhau; nhìn đúng module sẽ giúp mình chỉ chính xác chân nào cắm vào chân nào, tránh cắm nhầm VDD/GND.