MAX98357 사용 중 발생하는 틱(또는 팝) 소리는 오디오 신호(I2S 클럭)가 시작되거나 멈출 때, 칩이 켜지고 꺼지는 타이밍(전압 급변) 때문에 발생합니다.
이 문제를 해결하기 위해 가장 효과적인 하드웨어 및 소프트웨어 조치 방법들을 요약해 드립니다.
- 연결 방법: MAX98357 모듈의 SD 핀을 MCU(ESP32, 아두이노 등)의 남는 일반 GPIO 핀에 연결합니다. [1]
- 제어 로직 (소스 코드 수정):
- 지속적인 무음 출력: 오디오 데이터가 없을 때 I2S 버스를 닫지 마세요. 대신 값이 0인 데이터(더미 데이터/무음)를 i2s_write로 끊임없이 밀어 넣어 I2S 클럭(BCLK, LRCK)이 항상 유지되도록 코드를 수정해야 합니다. [1, 2]
- 라즈베리 파이 환경의 경우: ALSA 드라이버가 오디오 종료 후 칩을 비활성화하면서 소리가 나므로, 백그라운드에서 /dev/zero를 계속 재생해 주는 서비스(aplay 실행 상태 유지)를 등록하는 것이 대표적인 해결책입니다. [1, 2]
- 조치 방법: MAX98357 모듈의 VIN과 GND 핀 바로 옆(가장 가까운 곳)에 10µF 전해 커패시터와 0.1µF(100nF) 세라믹 커패시터를 병렬로 납땜해 주세요. 전류 공급이 안정해지면서 재생 도중 튀는 노이즈가 크게 줄어듭니다. [1]
- DMA 버퍼 지우기: 오디오 데이터를 처음 전송할 때 이전 버퍼 찌꺼기가 남아있으면 틱 소리가 날 수 있습니다. 재생 전에 버퍼를 초기화하는 함수(예: i2s_zero_dma_buffer())를 호출해 주세요. [1]
- 데이터 포맷 일치: MAX98357은 보통 16비트 Philips I2S 포맷에서 가장 안정적입니다. 소스 코드에서 데이터 포맷이나 비트 수가 정확히 일치하는지 확인하세요.
해결 방법
DMA에 오디오를 채우고 I2C 노이즈를 "마스킹"하려 함 → 노이즈가 데이터 경로가 아닌 전원 경로로 들어오기 때문에 효과 없음
이번 접근:
1. out->setVolume(0) + mp3->loop() x 2 → DMA가 0으로 채워짐 → MAX98357A 출력전압 ≈ 0V
2. ampMute(true) → 출력이 이미 0V에 가까운 상태에서 SD_MODE LOW → 팝 최소화
3. drawWord() + saveSession() → 앰프가 꺼져있어 I2C/SPI 노이즈가 스피커로 나오지 않음
4. ampMute(false) + out->setVolume(volume) → 정상 재생 재개
이전에 ampMute가 팝을 발생시켰던 이유는 오디오가 재생 중인 상태(출력 비제로)에서 SD_MODE를 전환했기 때문입니다. 이번엔 출력을 먼저 0으로 만들고 전환합니다.
최종 해결 방법
## 트랙 간 팝노이즈(틱·드드드) 완전 해결 과정 (2026-10-02)
### 증상
영어 단어 재생이 시작될 때 "드드드" 또는 "틱" 소리가 동시에 들림.
정확히 `loadNext()` 안의 `drawWord()` 호출 타이밍과 일치.
### 원인 A — I2S 드라이버 재설치로 인한 BCLK/LRCK 중단
`mp3->stop()` 내부에서 `i2s_driver_uninstall()` 호출 → I2S 비트클럭·좌우클럭 중단 → MAX98357A 출력 부동 → 재시작 시 전압 스텝 → 팝.
**해결:** `GainOutputI2S::stop()` no-op 오버라이드로 드라이버 재설치 차단. BCLK/LRCK를 프로그램 동안 연속 유지.
**부작용 — 스킵 발생:**
`stop()` no-op으로 `i2sOn=true` 상태가 유지되면 `AudioOutputI2S::begin()`이 **`false`를 반환**한다.
→ `mp3->begin()` 실패 → `isRunning()=false` → `loop()`에서 즉시 skip.
**해결:** `begin()` 도 오버라이드. `_started` 플래그로 최초 1회만 드라이버 설치, 이후 호출은 무조건 `true` 반환.
```cpp
bool begin() override {
if (_started) return true;
_started = true;
return AudioOutputI2S::begin();
}
bool stop() override { return true; }
```
> **규칙:** `stop()` no-op 오버라이드를 쓰면 반드시 `begin()`도 함께 오버라이드해야 한다.
> 짝을 맞추지 않으면 스킵이 발생한다.
---
### 원인 B — OLED I2C 스위칭 노이즈가 MAX98357A 전원 경로로 커플링
I2S 드라이버를 유지해도 `drawWord()` 실행 시 "드드드" 소리가 여전히 발생.
**원인 분석:**
SH1107 128×128 OLED를 `display.sendBuffer()`로 업데이트하면 I2C 100kHz로 2048 바이트 전송 → **약 180ms 동안 SCL이 100kHz로 스위칭**.
이 스위칭 전류가 VDD 라인에 노이즈를 만들고, MAX98357A가 이를 증폭 → "드드드" 소리.
**핵심:** 노이즈 경로는 I2S **데이터 경로**가 아니라 **전원 경로(VDD)**다.
→ DMA에 zeros를 채우거나 오디오를 미리 채우는 방법(데이터 경로 접근)으로는 해결 불가.
### 시도한 실패 접근들
| 시도 | 결과 | 실패 이유 |
| DMA에 zeros 512개 채우기 | 여전히 "드드드" | 전원 경로 노이즈는 데이터 경로로 차단 불가 |
| mp3->loop() 4회로 DMA에 오디오 사전 채우기 | 여전히 "드드드" | 오디오가 마스킹하기에 노이즈가 전원 경로에서 직접 합산됨 |
| ampMute(true/false) 토글 (오디오 재생 중) | 팝 발생 | 출력 비제로 상태에서 SD_MODE 전환 → 출력 캐패시터 방전 → 팝 |
| saveSession() 순서 이동 | 효과 없음 | 근본 원인(I2C 노이즈 경로)과 무관 |
최종 해결 — 출력 0 상태에서 앰프 뮤트 후 OLED 업데이트
```cpp
// loadNext() 내부
mp3->begin(source, out);
out->setVolume(0); // ① 게인 0
for (int i = 0; i < 2 && mp3->isRunning(); i++)
mp3->loop(); // ② DMA를 0으로 채움 → 출력 ≈ 0V
ampMute(true); // SD_MODE LOW // ③ 출력이 0에 가까울 때 뮤트 → 팝 없음
drawWord(path); // I2C 노이즈 발생해도 앰프 꺼짐 // ④ 노이즈 차단
saveSession(); // SPI 노이즈도 차단 // ⑤
ampMute(false); // SD_MODE HIGH // ⑥ 내부 soft-start로 팝 없이 재개
out->setVolume(volume); // ⑦ 볼륨 복원
```
**왜 이번엔 팝이 없나:**
이전 ampMute 시도는 오디오 재생 중(출력 비제로)에 SD_MODE를 전환해서 출력 캐패시터가 방전되며 팝이 났다.
이번엔 ①②로 출력을 먼저 0V에 가깝게 만든 뒤 ③에서 전환하므로 캐패시터에 방전할 전하가 없다.
언뮤트(⑥)는 MAX98357A 내부 soft-start 회로가 처리한다.
최종 상태 요약
- GainOutputI2S::stop() → no-op (I2S 드라이버 재설치 차단)
- GainOutputI2S::begin() → _started 플래그, 최초 1회만 실제 초기화
- loadNext() 내 OLED 업데이트: setVolume(0) → DMA zeros → ampMute(true) → drawWord() → ampMute(false) → setVolume(volume)
- 트랙 간 SD_MODE 상시 토글은 사용하지 않는다 (팝 원인)

'ESP32 Project' 카테고리의 다른 글
| ESP32-S3 자력계 magnetometer 나침반 (0) | 2026.10.03 |
|---|---|
| Practical Audio DSP Projects with the ESP32 교재 설명 (0) | 2026.09.29 |
| ESP32-P4 개발 자료 링크 모음 (0) | 2026.09.28 |
| ESP32를 소형 Wi-Fi 및 블루투스 보안 연구용 플랫폼 (0) | 2026.09.17 |
| 시계, 포모도로 기능, 타이머, 알람 기능을 하는 시계 1 (0) | 2026.09.16 |
| ESP32 소형 PC 성능 대시보드 (0) | 2026.09.11 |
| ESP32에서 구현하는 3D 그래픽 (0) | 2026.09.11 |
| ESP32 제품 개발 및 펌웨어 바이브 코딩 오프라인 강의 (0) | 2026.09.09 |
캐어랩